It has been a few dreadful days :-( I eventually get everything working. The first thing I did was to get rid of the interfaces in EMF genmodel. Essentially, you can change a flag to suppress separating interfaces and implementation classes.
In addition to that, using @XmlSeeAlso helps not only in marshalling but also unmarshalling. Finally, do not use @XmlMixed together with @XmlElement and @XmlElements. I added this flag accidentally, and it causes my program to crash without meaningful debug/output messages --- took me at least a full day to realize... Haven't got a chance to try XmlJavaTypeAdapters, will do so later... Thanks everyone! -Simon On Tue, Apr 19, 2011 at 7:15 AM, Sergey Beryozkin <[email protected]> wrote: > HI Simon > > On Tue, Apr 19, 2011 at 1:26 AM, Simon Chen <[email protected]> wrote: >> (Sorry Sergey for the dup message, I forgot to reply to all last time...) >> > > No problems, we'd just update the list aftewards otherwise:-) > >> It seems that I get all sorts of weird issues with EMF+JAXB. >> >> For example, if I have a base class of Customer and two inherited >> classes of GoodCustomer and BadCustomer. >> Then I have a WebStore as a >> container for a list of Customer objects. The mind-twisting (for me at >> least) problem is that if Customer is not defined as abstract in the >> ecore model, I cannot even create the JAXBContext for WebStore (well, >> actually WebStoreImpl for EMF), with a NoSuchElementException. If I >> change Customer to be abstract, then at least it works in this aspect. >> >> I tried plain java classes (hand-written, without interface/impl, >> without proxy), it works no matter Customer is abstract or not... > > What is WebStore, is it a root resource class or JAXB bean which your > JAX-RS service returns/updates ? > May be you have to add @XmlJavaTypeAdapter to WebStore field which > keeps the list of Customer interface impls... > > Cheers, Sergey > >> >> -Simon >> >> On Mon, Apr 18, 2011 at 11:02 AM, Sergey Beryozkin <[email protected]> >> wrote: >>> Sorry for the noise, I think I've got totally confused - no @XmlSeeAlso has >>> to be added to subclasses. But, I have a test where >>> >>> SuperBook extends Book, Book has @XmlSeeAlso pointing to SuperBook, and >>> without using JAXBElement (internally), xsi:type is not written when Book is >>> returned, however, no extra classes or jaxb.index is used, so that might >>> explain why... >>> >>> Cheers, Sergey >>> >>> >>> >>> On Mon, Apr 18, 2011 at 3:57 PM, Sergey Beryozkin <[email protected]> >>> wrote: >>>> >>>> That should work with adapters too, with @XmlSeeAlso. >>>> >>>> Actually, I remember now what adding a jaxbElementClassNames property >>>> (containing a CustomerImpl full class name only in this particular >>>> case) can >>>> do, it may help with avoiding adding @XmlSeeAlso to subclasses, I see a >>>> test >>>> where only a base class has @XmlSeeAlso - somehow JAXBElement figures it >>>> out >>>> that xsi:type has to be added... >>>> Adding jaxb.index extra classes for JAXBContext to include them should >>>> also help... >>>> >>>> thanks, Sergey >>>> >>>> On Mon, Apr 18, 2011 at 3:36 PM, Daniel Kulp <[email protected]> wrote: >>>>> >>>>> When dealing with polymorphism with JAXB, one thing that is often >>>>> required is >>>>> to add XmlSeeAlso annotations all over the place. In particular, on the >>>>> base >>>>> class, it's useful to have XmlSeeAlso point at the potential subclasses. >>>>> This allows the jaxb runtime to find the subclasses to instantiate and >>>>> will >>>>> usually result in the proper xsi:type attributes written out and such. >>>>> >>>>> If you haven't already tried it, I'd definitely suggest adding the >>>>> annotation >>>>> and seeing if that helps. >>>>> >>>>> Dan >>>>> >>>>> >>>>> On Friday 15 April 2011 4:02:17 PM Simon Chen wrote: >>>>> > Hi all, >>>>> > >>>>> > I've been playing with building a REST web service to handle >>>>> > polymorphism... It's a long post, but bear with me :-) >>>>> > >>>>> > In particular, I may have: >>>>> > >>>>> > @Path("/") >>>>> > class WebStore { >>>>> > @POST >>>>> > @Path("/customers/") >>>>> > Response addCustomer(Customer c) { >>>>> > ... >>>>> > } >>>>> > } >>>>> > >>>>> > But I have a base class of Customer, but also inherited classes of >>>>> > AwesomeCustomer, and SuperAwesomeCustomer. Things get more complicated >>>>> > when EMF kicks in, where I actually have a Customer interface and >>>>> > CustomerImpl class. >>>>> > >>>>> > The previous declaration doesn't work when I post a customer XML >>>>> > snippet, >>>>> > say: <customer><name>simon</name></customer> >>>>> > >>>>> > Because Customer is an interface, so cannot be annotated with >>>>> > @XmlRootElement. As a result, the error of "no message body reader can >>>>> > be found" is raised... >>>>> > >>>>> > If we change the POST function this way, it can work: >>>>> > @POST >>>>> > @Path("/customers/") >>>>> > Response addCustomer(CustomerImpl c) { >>>>> > ... >>>>> > } >>>>> > >>>>> > But, this breaks again, when I add the following: >>>>> > @POST >>>>> > @Path("/customers/") >>>>> > Response addCustomer(CustomerImpl c) { >>>>> > ... >>>>> > } >>>>> > @POST >>>>> > @Path("/customers/") >>>>> > Response addCustomer(AwesomeCustomerImpl c) { >>>>> > ... >>>>> > } >>>>> > @POST >>>>> > @Path("/customers/") >>>>> > Response addCustomer(SuperAwesomeCustomerImpl c) { >>>>> > ... >>>>> > } >>>>> > >>>>> > Here, if I post a SuperAwesomeCustomerImpl object to "/customers", the >>>>> > ws would find all the functions that can handle "POST to /customers", >>>>> > which will include all three functions above. However, in >>>>> > >>>>> > "src/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils. >>>>> > java", public static OperationResourceInfo findTargetMethod(), we have: >>>>> > >>>>> > if (!candidateList.isEmpty()) { >>>>> > Map.Entry<OperationResourceInfo, MultivaluedMap<String, >>>>> > String>> firstEntry = >>>>> > candidateList.entrySet().iterator().next(); >>>>> > //---------> This only looks at the first function that >>>>> > matches, while not look at the class hierarchy... >>>>> > values.clear(); >>>>> > values.putAll(firstEntry.getValue()); >>>>> > OperationResourceInfo ori = firstEntry.getKey(); >>>>> > >>>>> > >>>>> > Hopefully, I am not overwhelming everyone with too much information. >>>>> > But is there a fix to this problem? I guess maybe add some class >>>>> > hierarchy-awareness to findTargetMethod()? >>>>> > >>>>> > Thanks! >>>>> > -Simon >>>>> >>>>> -- >>>>> Daniel Kulp >>>>> [email protected] >>>>> http://dankulp.com/blog >>>>> Talend - http://www.talend.com >>>> >>>> >>>> Application Integration Division of Talend >>>> http://sberyozkin.blogspot.com >>> >>> >>> >>> -- >>> Sergey Beryozkin >>> >>> Application Integration Division of Talend >>> http://sberyozkin.blogspot.com >>> >> >
