Sunday, December 18, 2011

JAXB can't handle interfaces

If you get the following error:

Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions com.unicacorp.interact.api.NameValuePair is an interface, and JAXB can't handle interfaces. this problem is related to the following location:
at com.unicacorp.interact.api.NameValuePair
at public com.unicacorp.interact.api.NameValuePair[] com.singtel
.ma.rto.jaxws.GetCustomerOffers.arg6
at com.singtel.ma.rto.jaxws.GetCustomerOffershttp://www.blogger.com/img/blank.gif
com.unicacorp.interact.api.NameValuePair does not have a no-arg default construc
tor.
this problem is related to the following location:
at com.unicacorp.interact.api.NameValuePairhttp://www.blogger.com/img/blank.gif
at public com.unicacorp.interact.api.NameValuePair[] com.singtel
.ma.rto.jaxws.GetCustomerOffers.arg6
at com.singtel.ma.rto.jaxws.GetCustomerOffers


Make sure you are using the right classes (not interface). If you really need to use interface, check out this link

Adding the "@XmlJavaTypeAdapter(AnyTypeAdapter.class)" annotation to the object interface solved this problem by telling JAXB to use a special type adapter needed for interfaces. @XmlJavaTypeAdapter(AnyTypeAdapter.class) @XmlRootElement public interface MyObject { ... }
Note: The AnyTypeAdapter.java source code is very simple and can be readily found online.


Marshalling Error Encountered

It turns out that adding the AnyTypeAdapter annotation was only part of the solution. Although this annotation lets the web service start successfully, the first call to getMyObjects() resulted in a marshalling error.
INFO: Interceptor has thrown exception, unwinding noworg.apache.cxf.interceptor.Fault: Marshalling Error: class com.attivio.webservice.WebServiceTest$MyObjectImpl1 nor any of its super class is known to this context. Caused by: javax.xml.bind.MarshalException - with linked exception: [javax.xml.bind.JAXBException: class com.attivio.webservice.WebServiceTest$MyObjectImpl1 nor any of its super class is known to this context.]
The final piece of the puzzle was solved by creating a per-module interface, MyApi1, which extends MyApi and has the “@XmlSeeAlso({MyObjectImpl1.class, MyObjectImpl2.class})” annotation. By extending this interface and registering it as the endpoint class, JAXB was able to find the appropriate implementations of the MyObject interface for serialization. By putting the annotation on a module specific interface, instead of the base interface, different modules can have different objects and APIs without the need to know details of the other modules.
@WebService @XmlSeeAlso({MyObjectImpl1.class, MyObjectImpl2.class}) public interface MyApi1 extends MyApi { } public static class MyApiImpl implements MyApi1 { ... }