users@jersey.java.net

[Jersey] Re: Problem unmarshalling entity to correct JAXB object

From: Jakub Podlesak <jakub.podlesak_at_oracle.com>
Date: Tue, 08 Nov 2011 18:36:34 +0100

Hi Farrukh,

I meant to keep the client intact, and update the server to only take
the RemoveObjectsRequest entity:
public Response putRequest(RemoveObjectsRequest req)
the above should work fine.

What might help you to fix the original issue would be to provide a
JAXBContext resolver
to return a JAXBContext aware of all the JAXB beans involved in your
RegistryRequestType hierarchy, i.e something like follows:

     @Provider
     public class JAXBContextResolver implements
ContextResolver<JAXBContext> {
         private JAXBContext context;
         private final Class[] cTypes = {RegistryRequestType.class,
RemoveObjectsRequest.class /* all other classes extending the
RegistryRequestType class */ };
         private final Set<Class> types;
         public JAXBContextResolver() {
             try {
                 this.types = new HashSet<Class>(Arrays.asList(cTypes));
                 this.context = JAXBContext.newInstance(cTypes);
             } catch (JAXBException ex) {
                 throw new RuntimeException(ex);
             }
         }

         @Override
         public JAXBContext getContext(Class<?> c) {
             return types.contains(c) ? context : null;
         }
     }

Does it help?

~Jakub


On 8.11.2011 15:38, Farrukh Najmi wrote:
>
> Hi Jakub,
>
> I did not understand what you want me to try. The request entity needs
> to be a RemoveObjectsRequest element. In my JAXB generated bindings
> there are the following classes:
>
> public class RegistryRequestType {
> ...
> }
>
> public class RemoveObjectsRequest extends RegistryRequestType {
> ...
> }
>
> In my resource method I expect RegistryRequestType param to have the
> specific sub-type of RegistryRequestType (e.g. RemoveObjectsRequest)
> based on the element that was in teh request entity.
>
> With that summary what were you suggesting I try? Also, why is my
> assumption on expected behavior incorrect? It seems to make sense that
> jersey server should be able to unmarshall a RemoveObjectsRequest type
> and pass it as a RegistryRequestType to my resource method.
>
> Thank you for your kind help.
>
> On 11/08/2011 08:31 AM, Jakub Podlesak wrote:
>> Possibly. Do you have any chance to try out with the same type,
>> ideally just RemoveObjectsRequest?
>>
>> ~Jakub
>>
>> On 8.11.2011 13:27, Farrukh Najmi wrote:
>>> Hi Jakub,
>>>
>>> At the beginin of this thread I mentioned that RemoveObjectsRequest
>>> extends RegistryRequestType. Therefor I assumed that it was OK to
>>> pass a RemoveObjectsRequest where the resource method is expecting a
>>> RegistryRequestType. Am I wrong in this assumption?
>>>
>>> On 11/08/2011 03:44 AM, Jakub Podlesak wrote:
>>>> Hi Farrukh,
>>>>
>>>> please see in lines...
>>>>
>>>> On 7.11.2011 21:09, Farrukh Najmi wrote:
>>>>>
>>>>> Hi Jakub,
>>>>>
>>>>> There does not seem to be any difference whether I do either of
>>>>> the following on client side:
>>>>>
>>>>> RemoveObjectsRequest removeRequest = ...;
>>>>
>>>> The above removeRequest is of the *RemoveObjectsRequest* type
>>>>
>>>>> ClientResponse resp =
>>>>> webResource.accept(MediaType.APPLICATION_XML).
>>>>> type(MediaType.APPLICATION_XML).
>>>>> entity(removeRequest).
>>>>
>>>> and is passed here to the client
>>>>
>>>>> put(ClientResponse.class);
>>>>>
>>>>> Or.
>>>>>
>>>>> ClientResponse resp =
>>>>> webResource.accept(MediaType.APPLICATION_XML).
>>>>> type(MediaType.APPLICATION_XML).
>>>>> entity(BindingUtility.marshalObject(removeRequest)).
>>>>> //marshalls RemoveObjectsRequest object to a String
>>>>> put(ClientResponse.class);
>>>>>
>>>>> In both cases if the resource method signature is:
>>>>>
>>>>> public Response putRequest(RegistryRequestType req)
>>>>
>>>> while above you are consuming *RegistryRequestType*, you mention
>>>> this also in the following line.
>>>> My suggestion was to try sending and consuming the very same type.
>>>>
>>>> ~Jakub
>>>>
>>>>>
>>>>> then I get a RegistryRequestType instance rather than a
>>>>> RemoveObjectsRequest instance.
>>>>>
>>>>> The workaround I did on the server side to change the method
>>>>> signature to:
>>>>>
>>>>> public Response putRequest(String entityStr);
>>>>>
>>>>> and then unmarshalling from string manually works in both cases.
>>>>>
>>>>> This is not high priority but I am curious why this does not work
>>>>> as expected. Making a reproducable test case is not trivial but I
>>>>> would be glad to help debug this further if you think it could be
>>>>> an issue that needs filiing and eventual fixing.
>>>>>
>>>>> Thanks very much for your help.
>>>>>
>>>>> On 11/07/2011 11:41 AM, Jakub Podlesak wrote:
>>>>>> Hi Farrukh,
>>>>>>
>>>>>> The problem was that on the client side you referred to your own
>>>>>> BindingUtility to serialize
>>>>>> the XML for you, while on the server side you expected Jersey to
>>>>>> automatically
>>>>>> pick up whatever the BindingUtility produced.
>>>>>>
>>>>>> What happens if you directly passed a RegistryRequestType to the
>>>>>> web resource entity method on the client side?
>>>>>> I presume that should work all right for you...
>>>>>>
>>>>>> ~Jakub
>>>>>>
>>>>>>
>>>>>> On 7.11.2011 16:15, Farrukh Najmi wrote:
>>>>>>> On 11/07/2011 09:18 AM, Farrukh Najmi wrote:
>>>>>>>> Hi Guys,
>>>>>>>>
>>>>>>>> I have an XML Schema as follows:
>>>>>>>>
>>>>>>>> <complexType name="RegistryRequestType">
>>>>>>>> ...
>>>>>>>> </complexType>
>>>>>>>>
>>>>>>>> <element name="RemoveObjectsRequest">
>>>>>>>> <complexType>
>>>>>>>> <complexContent>
>>>>>>>> <extension base="rs:RegistryRequestType">
>>>>>>>> ....
>>>>>>>> </extension>
>>>>>>>> </complexContent>
>>>>>>>> </complexType>
>>>>>>>>
>>>>>>>> I use JAXB to generate bindings for above schema as follows:
>>>>>>>>
>>>>>>>> public class RegistryRequestType {
>>>>>>>> ...
>>>>>>>> }
>>>>>>>>
>>>>>>>> public class RemoveObjectsRequest extends RegistryRequestType {
>>>>>>>> ...
>>>>>>>> }
>>>>>>>>
>>>>>>>> I have a jersey server resource method as follows:
>>>>>>>>
>>>>>>>> @PUT
>>>>>>>> @Consumes({"application/xml"})
>>>>>>>> @Produces({"application/xml"})
>>>>>>>> @Path("/requests")
>>>>>>>> public Response putRequest(RegistryRequestType req) {
>>>>>>>> }
>>>>>>>>
>>>>>>>> I issue a client PUT request where entity is a
>>>>>>>> RemoveObjectsRequest element using following code:
>>>>>>>>
>>>>>>>> RemoveObjectsRequest removeRequest = ...
>>>>>>>> ClientResponse resp =
>>>>>>>> webResource.accept(MediaType.APPLICATION_XML).
>>>>>>>> type(MediaType.APPLICATION_XML).
>>>>>>>> entity(BindingUtility.marshalObject(removeRequest)).
>>>>>>>> //marshalls RemoveObjectsRequest object to String
>>>>>>>> put(ClientResponse.class);
>>>>>>>>
>>>>>>>> When my putRequest() resource method is called, I expect the
>>>>>>>> req param to be set to an object of type RemoveObjectsRequest.
>>>>>>>> Instead it is set to a an object where the type is
>>>>>>>> RegistryRequestType and data members of the
>>>>>>>> RemoveObjectsRequest are not set.
>>>>>>>>
>>>>>>>> Is this a issue in jersey (note I am using 1.10) or do I have
>>>>>>>> faulty assumption on what to expect?
>>>>>>>>
>>>>>>>> If the expected behavior is not possible then what is the way
>>>>>>>> to get the raw entity from the request within my resource
>>>>>>>> method so I can unmarshall it as needed.
>>>>>>>>
>>>>>>>> Thank you for your help.
>>>>>>>>
>>>>>>>
>>>>>>> I was able to workaround the issue by specifying a String param
>>>>>>> in my resource method for receiving the request entity. I then
>>>>>>> used my JAXB unmarshaller to unmarshall from a StringReader
>>>>>>> created with that String.
>>>>>>>
>>>>>>> @PUT
>>>>>>> @Consumes({"application/xml"})
>>>>>>> @Produces({"application/xml"})
>>>>>>> @Path("/requests")
>>>>>>> public Response putRequest(String entityStr) {
>>>>>>> try {
>>>>>>> StringReader reader = new StringReader(entityStr);
>>>>>>> Unmarshaller u = ...;
>>>>>>> RegistryRequestType req = (RegistryRequestType)
>>>>>>> u.unmarshal(reader);
>>>>>>>
>>>>>>> //The req object is now correctly an instance of
>>>>>>> RemoveObjectsRequest
>>>>>>>
>>>>>>> ...
>>>>>>> return response;
>>>>>>> } catch (JAXBException ex) {
>>>>>>> ...
>>>>>>> }
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>> I am still curious why the behavior I expected is not what
>>>>>>> jersey server does.
>>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>
>
>