与JAXB相关:如何实现与JAXB兼容的变体包装器类?,我尝试使用JAXBElement
来表示"变体"或"任意类型"。
编组正常,但在解组期间,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)
运行示例:
(提示:JAXBHelper是从utils- api派生的,但只是您解组和编组例程的简短形式)
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>