2016-04-27 10 views
0

Ich habe einen Web-Service Ich habe einen Proxy nennen erzeugt unter Verwendung mit xcj (für .xsd) und wsimport (für .wsdl) Definitionen. Es ist extern (d. H. Kann es nicht bearbeiten), riesig und ständig veränderbar (kann die generierten Klassen nicht manuell anpassen).JAX-WS (JAXB) und unmarshalling gemischt xs: anyType

Es hat eine Superklasse-ähnliche xs:anyType Element mit mixed="true", ähnlich wie im Beispiel unten.

<Foo type="Bar"> 
    <id>123</id> 
</Foo> 

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="Foo"> 
     <xs:complexType> 
      <xs:complexContent mixed="true"> 
       <xs:extension base="xs:anyType"> 
        <xs:attribute name="type" type="xs:string"/> 
       </xs:extension> 
      </xs:complexContent> 
     </xs:complexType> 
    </xs:element> 

    <xs:element name="Bar"> 
     <xs:complexType> 
      <xs:sequence> 
       <xs:element name="id" type="xs:int"/> 
       <xs:element name="name" type="xs:string"/> 
      </xs:sequence> 
     </xs:complexType> 
    </xs:element> 
</xs:schema> 

xjc/wsimport erzeugt Foo als

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "", propOrder = { "content" }) 
@XmlRootElement(name = "Foo") 
public class Foo { 
    @XmlMixed 
    @XmlAnyElement 
    protected List<Object> content; 
    @XmlAttribute(name = "type") 
    protected String type; 
    @XmlAnyAttribute 
    private Map<QName, String> otherAttributes = new HashMap<QName, String>(); 

I kann Marshall ein Foo Objekt folgt auf seine wurzel weniger Formular Document.getChildNodes() (obwohl ich eine sauberere Weg zu finden nichts ausmacht), aber ich kann nicht herausfinden, wie die Antwort content Liste (die ArrayList<ElementNSImpl> ist, nachdem Proxy damit fertig ist) zu entpacken Antwort auf stark typisierte Bar?

public static void main(String[] args) throws Exception { 
    Foo foo = new Foo(); 
    foo.type = "Bar"; 

    Bar bar = new Bar(); 
    bar.id = 123; 

    JAXBContext context = JAXBContext.newInstance(Foo.class, Bar.class); 
    Marshaller marshaller = context.createMarshaller(); 
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

    Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 
    marshaller.marshal(bar, document); 

    NodeList nodes = document.getFirstChild().getChildNodes(); 
    foo.content = IntStream.range(0, nodes.getLength()).mapToObj(nodes::item).collect(Collectors.toList()); 

    StringWriter writer = new StringWriter(); 
    marshaller.marshal(foo, writer); 
    System.out.println(writer); 

    Unmarshaller unmarshaller = context.createUnmarshaller(); 

    // ??? 
    unmarshaller.unmarshal(foo.content, Bar.class); 
} 

Antwort

0

Ich denke, ich habe es gelöst. Upvotes zu wem auch immer eine sauberere Lösung kommt.

public static List<Object> marshal(Object value) { 
    try { 
     Class<?> type = value.getClass(); 
     if (type.isAnonymousClass()) 
      type = type.getSuperclass(); 

     Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 
     Marshaller marshaller = JAXBContext.newInstance(type).createMarshaller(); 
     marshaller.marshal(new JAXBElement<>(QName.valueOf("root"), Object.class, value), document); 

     NodeList nodes = document.getDocumentElement().getChildNodes(); 
     return IntStream.range(0, nodes.getLength()).mapToObj(nodes::item).collect(Collectors.toList()); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
} 

public static <T> T unmarshal(List<Object> content, Map<QName, String> attributes, Class<T> type) { 
    try { 
     Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 
     document.appendChild(document.createElement("root")); 

     if (attributes != null) 
      attributes.forEach((q, s) -> document.getDocumentElement().setAttribute(q.getLocalPart(), s)); 

     if (content != null) 
      content.forEach(o -> document.getDocumentElement().appendChild(document.importNode((Node) o, true))); 

     Unmarshaller unmarshaller = JAXBContext.newInstance(type).createUnmarshaller(); 
     return unmarshaller.unmarshal(document, type).getValue(); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
}