Skip to main content

@XmlJavaTypeAdapter clarification

1 reply [Last post]
whitfordny
Offline
Joined: 2006-09-24

I put together a test case similar to what is illustrated at:
https://jaxb.dev.java.net/guide/XML_layout_and_in_memory_data_layout.htm...
and here:
http://weblogs.java.net/blog/kohsuke/archive/2005/09/using_jaxb_20s.html

I declared a Color object, defined a ColorAdapter, and declared the @XmlJavaTypeAdapter to the package. Alas, it isn't getting called... If you consider the following sample code:

JAXBContext jc = JAXBContext.newInstance(Color.class);
// Note that a dump of the context confirms that com.acme.Color is listed!
//System.out.println("JAXBContext: " + jc.toString());

Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

Color color = Color.RED;

// Case 1: The following line works, but it does NOT call the ColorAdapter...
m.marshal( new JAXBElement( new QName("", "rootTag"), Color.class, color ), System.out);

// Case 2: This fails...
m.marshal(color, System.out);

Case 1 "works" (doesn't error), but the output clearly shows that the ColorAdapter is not getting called.

Case 2 throws a javax.xml.bind.MarshalException exception:

javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.SAXException2: unable to marshal type "com.acme.Color" as an element because it is missing an @XmlRootElement annotation]
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:
328)
testMarshalling : javax.xml.bind.MarshalException
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.jav
a:254)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshal
lerImpl.java:75)
at resty.AppTest.testMarshalling(AppTest.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
- with linked exception:
[com.sun.istack.SAXException2: unable to marshal type "com.acme.Color" as an element because it is missing an @XmlRootElement annotation]
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:213)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)
Caused by: com.sun.istack.SAXException2: unable to marshal type "com.acme.Color"
as an element because it is missing an @XmlRootElement annotation
at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:244)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:303)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:490)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:325)
... 29 more

Note that my Color object represents a third-party class -- a class where I can't just annotate it with @XmlRootElement. Hence, why I am looking at @XmlJavaTypeAdapter.

Can somebody please tell me why my adapter is not getting called, and what I can do about customizing the marshaling of a third-party class?

Note that I am using JAXB 2.1.8.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
whitfordny
Offline
Joined: 2006-09-24

I traced this test case into [b]PropertyInfoImpl.java[/b] and am very surprised to see that [i]getApplicableAdapter[/i] is being called with T being an "int" -- but parent.clazz is "com.acme.Color". Alas, this is always returning null -- instead of the adapter that I want to use...

jta is set to be the ColorAdapter, as expected. But then the isApplicable call returns false because T is an int (instead of a Color). getApplicableAdapter is never called with T being a Color. Is this a bug?

private XmlJavaTypeAdapter getApplicableAdapter(T type) {
XmlJavaTypeAdapter jta = seed.readAnnotation(XmlJavaTypeAdapter.class);
if(jta!=null && isApplicable(jta,type))
return jta;

// check the applicable adapters on the package
XmlJavaTypeAdapters jtas = reader().getPackageAnnotation(XmlJavaTypeAdapters.class, parent.clazz, seed );
if(jtas!=null) {
for (XmlJavaTypeAdapter xjta : jtas.value()) {
if(isApplicable(xjta,type))
return xjta;
}
}
jta = reader().getPackageAnnotation(XmlJavaTypeAdapter.class, parent.clazz, seed );
if(isApplicable(jta,type))
return jta;

// then on the target class
C refType = nav().asDecl(type);
if(refType!=null) {
jta = reader().getClassAnnotation(XmlJavaTypeAdapter.class, refType, seed );
if(jta!=null && isApplicable(jta,type)) // the one on the type always apply.
return jta;
}

return null;
}

I have attached a test case that I am using to debug the jaxb implementation.

BTW... I see a TODO comment in the implementation of Navigator.java on the isSubClassOf method that says, "[i]TODO: should this method take T or C?[/i]" I am wondering if Ts and Cs are being mixed up somewhere along the way, and that is my root cause...

I just clarified where in the code the "failure" happens.

Message was edited by: whitfordny