JAXB:无法解组JAXBElement <! - ? - >,而是获取ElementNSImpl

时间:2011-07-21 11:32:58

标签: java xml dom jaxb variant

JAXB: How to implement a JAXB-compatible variant wrapper class?相关,我尝试使用JAXBElement来表示“变体”或“任意类型”。

编组运行正常,但在Unmarshalling期间,JAXB尝试将ElementNSImpl分配到JAXBElement字段。

测试代码

(适用拷贝+膏+运行)

import static java.lang.System.*;
import java.io.*;
import java.util.*;

import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.*;

import org.junit.*;

public class _JaxbElementProblem {

    @XmlRootElement
    @XmlType
    @XmlAccessorType(XmlAccessType.NONE)
    static class MyObject {

        public static final QName VARIANT_NAME = new QName("QQQ");

        @XmlAnyElement(lax = true)
        private JAXBElement<Object> single = null;
        @XmlElementWrapper(name = "elements")
        @XmlAnyElement(lax = true)
        final List<JAXBElement<Object>> elements =
                new LinkedList<JAXBElement<Object>>();

        @SuppressWarnings("unused")
        private MyObject() {
        }

        public MyObject(Object o) {
            single = new JAXBElement<Object>(VARIANT_NAME, Object.class, o);
        }

        public Object getSingle() {
            return single.getValue();
        }

        public List<Object> getElements() {
            List<Object> ret = new LinkedList<Object>();

            for (JAXBElement<?> e : elements) {
                ret.add(e.getValue());
            }

            return ret;
        }

        @Override
        public String toString() {
            return "MyObject (single=" + single.getValue() + "; elements: "
                    + getElements() + ")";
        }

    }

    private static final JAXBContext C;
    private static final Marshaller M;
    private static final Unmarshaller U;

    static {
        try {
            C = JAXBContext.newInstance(MyObject.class);

            M = C.createMarshaller();
            U = C.createUnmarshaller();

            M.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        } catch (JAXBException ex) {
            throw new Error(ex);
        }
    }

    private void testMarshalUnmarshal(Object root) throws Exception {
        out.println("\nMARSHALLED - - - - - - - - - - - - - - - - - - - -");
        StringWriter sw = new StringWriter();
        M.marshal(root, sw);
        out.println(sw.toString() + "\n");

        out.println("\nUNMARSHALLED - - - - - - - - - - - - - - - - - - - -");
        Object reunmarshalled = U.unmarshal(new StringReader(sw.toString()));
        out.println(reunmarshalled + "\n");
    }

    @Before
    public void before() {
        out.println("\n= = = = = = = = = = = = = = = = = = = =");
    }

    @Test
    public void test1() throws Exception {
        MyObject root = new MyObject(Integer.valueOf(12345));
        testMarshalUnmarshal(root);
    }

    @Test
    public void test2() throws Exception {
        MyObject sub = new MyObject(Integer.valueOf(12345));
        MyObject root = new MyObject(sub);
        testMarshalUnmarshal(root);
    }

    @Test
    public void test3() throws Exception {
        MyObject oSub = new MyObject(Integer.valueOf(12345));
        List<MyObject> oSubs =
                Arrays.asList(new MyObject("sub-1"), new MyObject("sub-2"),
                        new MyObject("sub-3"));

        MyObject root = new MyObject(oSub);
        for (MyObject o : oSubs) {
            root.elements.add(new JAXBElement<Object>(MyObject.VARIANT_NAME,
                    Object.class, o));
        }

        testMarshalUnmarshal(root);
    }
}

测试输出

(正如您所见,不会发生解组)

= = = = = = = = = = = = = = = = = = = =

MARSHALLED - - - - - - - - - - - - - - - - - - - -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myObject>
    <QQQ xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">12345</QQQ>
    <elements/>
</myObject>



UNMARSHALLED - - - - - - - - - - - - - - - - - - - -

= = = = = = = = = = = = = = = = = = = =

MARSHALLED - - - - - - - - - - - - - - - - - - - -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myObject>
    <QQQ xsi:type="myObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <QQQ xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema">12345</QQQ>
        <elements/>
    </QQQ>
    <elements/>
</myObject>



UNMARSHALLED - - - - - - - - - - - - - - - - - - - -

= = = = = = = = = = = = = = = = = = = =

MARSHALLED - - - - - - - - - - - - - - - - - - - -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myObject>
    <QQQ xsi:type="myObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <QQQ xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema">12345</QQQ>
        <elements/>
    </QQQ>
    <elements>
        <QQQ xsi:type="myObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <QQQ xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">sub-1</QQQ>
            <elements/>
        </QQQ>
        <QQQ xsi:type="myObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <QQQ xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">sub-2</QQQ>
            <elements/>
        </QQQ>
        <QQQ xsi:type="myObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <QQQ xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">sub-3</QQQ>
            <elements/>
        </QQQ>
    </elements>
</myObject>



UNMARSHALLED - - - - - - - - - - - - - - - - - - - -

解组例外

java.lang.IllegalArgumentException: Can not set javax.xml.bind.JAXBElement field my._JaxbElementProblem$MyObject.single to com.sun.org.apache.xerces.internal.dom.ElementNSImpl
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
at java.lang.reflect.Field.set(Field.java:657)
at com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$FieldReflection.set(Accessor.java:234)
at com.sun.xml.internal.bind.v2.runtime.reflect.Accessor.receive(Accessor.java:160)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.endElement(UnmarshallingContext.java:507)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.endElement(SAXConnector.java:145)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:601)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1782)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2938)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:200)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:173)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:137)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:194)
at my._JaxbElementProblem.testMarshalUnmarshal(_JaxbElementProblem.java:84)
at my._JaxbElementProblem.test3(_JaxbElementProblem.java:119)

1 个答案:

答案 0 :(得分:0)

运行示例:

(提示:JAXBHelper来自utils-apl派生,但只是你解组和编组程序的简短形式)

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import org.junit.Test;
import org.omnaest.utils.xml.JAXBXMLHelper;

public class JAXBAnyElementTest
{
  @XmlType
  @XmlAccessorType(XmlAccessType.FIELD)
  protected static class TestSubEntity
  {
    /* ********************************************** Variables ********************************************** */
    @XmlElement
    private String fieldString  = null;
    @XmlElement
    private int    fieldInteger = -1;

    /* ********************************************** Methods ********************************************** */

    /**
     * @see TestSubEntity
     */
    public TestSubEntity()
    {
      super();
    }

    /**
     * @see TestSubEntity
     * @param fieldString
     * @param fieldInteger
     */
    public TestSubEntity( String fieldString, int fieldInteger )
    {
      super();
      this.fieldString = fieldString;
      this.fieldInteger = fieldInteger;
    }

    /**
     * @return the fieldString
     */
    public String getFieldString()
    {
      return this.fieldString;
    }

    /**
     * @param fieldString
     *          the fieldString to set
     */
    public void setFieldString( String fieldString )
    {
      this.fieldString = fieldString;
    }

    /**
     * @return the fieldInteger
     */
    public int getFieldInteger()
    {
      return this.fieldInteger;
    }

    /**
     * @param fieldInteger
     *          the fieldInteger to set
     */
    public void setFieldInteger( int fieldInteger )
    {
      this.fieldInteger = fieldInteger;
    }

    @Override
    public int hashCode()
    {
      final int prime = 31;
      int result = 1;
      result = prime * result + this.fieldInteger;
      result = prime * result + ( ( this.fieldString == null ) ? 0 : this.fieldString.hashCode() );
      return result;
    }

    @Override
    public boolean equals( Object obj )
    {
      if ( this == obj )
      {
        return true;
      }
      if ( obj == null )
      {
        return false;
      }
      if ( !( obj instanceof TestSubEntity ) )
      {
        return false;
      }
      TestSubEntity other = (TestSubEntity) obj;
      if ( this.fieldInteger != other.fieldInteger )
      {
        return false;
      }
      if ( this.fieldString == null )
      {
        if ( other.fieldString != null )
        {
          return false;
        }
      }
      else if ( !this.fieldString.equals( other.fieldString ) )
      {
        return false;
      }
      return true;
    }

  }

  @XmlRootElement
  @XmlAccessorType(XmlAccessType.FIELD)
  protected static class TestEntity
  {
    @XmlElements({ @XmlElement(name = "int", type = Integer.class), @XmlElement(name = "string", type = String.class),
        @XmlElement(name = "testsubentity", type = TestSubEntity.class), @XmlElement(name = "other") })
    private List<Object> anyElementList = null;

    /**
     * @return the anyElementList
     */
    public List<Object> getAnyElementList()
    {
      return this.anyElementList;
    }

    /**
     * @param anyElementList
     *          the anyElementList to set
     */
    public void setAnyElementList( List<Object> anyElementList )
    {
      this.anyElementList = anyElementList;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode()
    {
      final int prime = 31;
      int result = 1;
      result = prime * result + ( ( this.anyElementList == null ) ? 0 : this.anyElementList.hashCode() );
      return result;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals( Object obj )
    {
      if ( this == obj )
      {
        return true;
      }
      if ( obj == null )
      {
        return false;
      }
      if ( !( obj instanceof TestEntity ) )
      {
        return false;
      }
      TestEntity other = (TestEntity) obj;
      if ( this.anyElementList == null )
      {
        if ( other.anyElementList != null )
        {
          return false;
        }
      }
      else if ( !this.anyElementList.equals( other.anyElementList ) )
      {
        return false;
      }
      return true;
    }

  }

  @SuppressWarnings("cast")
  @Test
  public void test()
  {
    //
    final TestEntity testEntity = new TestEntity();

    //
    final List<Object> anyElementList = Arrays.asList( (Object) "a", Integer.valueOf( 1 ), Boolean.valueOf( true ),
                                                       new TestSubEntity( "field1", 1 ) );
    testEntity.setAnyElementList( anyElementList );

    //
    final String objectAsXML = JAXBXMLHelper.storeObjectAsXML( testEntity );
    System.out.println( objectAsXML );

    //
    final TestEntity objectFromXML = JAXBXMLHelper.loadObjectFromXML( objectAsXML, TestEntity.class );
    assertEquals( testEntity, objectFromXML );
  }
}

输出:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<testEntity>
    <string>a</string>
    <int>1</int>
    <other xsi:type="xs:boolean" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">true</other>
    <testsubentity>
        <fieldString>field1</fieldString>
        <fieldInteger>1</fieldInteger>
    </testsubentity>
</testEntity>