users@jersey.java.net

Re: [Jersey] Custom Natural JAXBContextResolver Problem - Single Element Arrays

From: Jakub Podlesak <Jakub.Podlesak_at_Sun.COM>
Date: Fri, 09 Oct 2009 17:06:23 +0200

Hi James,

great news, i am glad it works for you,

thanks,

~Jakub

On Fri, Oct 09, 2009 at 07:54:46AM -0700, James Allchin wrote:
> Thanks Jakub - for your assistance - ultimately it enabled me to solve the problem.
>
> I got the test case you sent me working just fine. I then tried deploying against my tomcat instance which also worked fine.
>
> This was a good start :-)
>
> I then modified my own netbeans project to include your test files - running both as a grizzly server and on tomcat.
>
> In the end it came down to environmental issues with netbeans (and library dependencies) - which aren't fully resolved but the good news it is now in a working state.
>
> Thanks for your assistance - and apologies that it was a bit of red herring. The test case really did help though.
>
> Cheers
>
> James
> ________________________________________
> From: Jakub.Podlesak_at_Sun.COM [Jakub.Podlesak_at_Sun.COM]
> Sent: 08 October 2009 16:25
> To: users_at_jersey.dev.java.net
> Cc: James Allchin
> Subject: Re: [Jersey] Custom Natural JAXBContextResolver Problem - Single Element Arrays
>
> Hi James,
>
> one more thing, please see the comments inline....
>
> On Mon, Oct 05, 2009 at 12:25:55PM -0700, James Allchin wrote:
> > Hi All,
> >
> > I have a ContextResolver so that I can use Natural JSON notation:
> >
> > package com.knowledgemill.rest.main;
> >
> > import com.knowledgemill.entities.*;
> >
> > import com.sun.jersey.api.json.JSONJAXBContext;
> > import com.sun.jersey.api.json.JSONConfiguration;
> > import java.util.HashMap;
> > import java.util.HashSet;
> > import java.util.Map;
> > import javax.ws.rs.ext.ContextResolver;
> > import javax.ws.rs.ext.Provider;
> > import javax.xml.bind.JAXBContext;
> >
> > /*
> > * This class is used to make sure that when using JSON when an array contains a single
> > * element it still comes back as an array - makes it much easier to deal with
> > */
> >
> >
> > @Provider
> > public class JAXBContextResolver implements ContextResolver<JAXBContext> {
> >
> > private JAXBContext context;
> >
> > private Class<?>[] types = {
> > Artifact.class
> > , ArtifactPermission.class
> > , AttachedDoc.class
> > , AttachedDocArtifact.class
> > , AuditMessage.class
> > , Container.class
> > , ContainerPermission.class
> > , Context.class
> > , ContextFolder.class
> > , Credential.class
> > , DBLogMessage.class
> > , EmailArtifact.class
> > , EmailRecipient.class
> > , ExtendedAttribute.class
> > , ExtendedEmail.class
> > , Group.class
> > , InternalArtifact.class
> > , InternalUser.class
> > , ManagedDocArtifact.class
> > , StorageTier.class
> > , SystemAttribute.class
> > , TreeNode.class
> > , User.class
> > , UserEmailAddress.class
> > };
> >
> >
> > public JAXBContextResolver() throws Exception {
> > Map props = new HashMap<String, Object>();
> > this.context = new JSONJAXBContext(JSONConfiguration.natural().build(), types);
> > }
> >
> > public JAXBContext getContext(Class<?> objectType) {
> > for (Class<?> type : types) {
> > if (type == objectType) {
> > return context;
> > }
> > }
> > return null;
> > }
> >
> >
> > }
> >
> >
> > As you can see I have a number of classes which I have specified should be targeted by the this ContextResolver.
> >
> > Now according to the documentation, the NATURAL configuration should mean that single element arrays will indeed be respected as a array within JSON (instead of returning a single object).
> >
> > If I take one of my methods which returns List<UserEmailAddress>:
> >
> > @GET
> > @Path("user/{userId}/users/{targetUserId}/emailaddresses/")
> > @Produces({"application/xml","application/json"})
> > public List<UserEmailAddress> getUserEmailAddresses (@PathParam("userId") String userId
> > , @PathParam("targetUserId") String targetUserId
> > ) {
> >
> > List<UserEmailAddress> returnedEmailAddresses = null;
> > try {
> > logger.debug("userId value is " + userId);
> > returnedEmailAddresses = dA.getUserEmailAddresses( targetUserId);
> > }
> > catch (Exception e) {
> > e.printStackTrace();
> > }
> > return returnedEmailAddresses;
> > }
> >
> > If I exercise this call (using JSON) where it returns multiple elements - I end up with a response shown below:
> >
> > {"UserEmailAddress": [
> > {
> > "userId": "7452272EBA160D9AE040A8C048010EEB",
> > "smtpAddress": "david.campbell_at_knowledgemill.com",
> > "primary": "false",
> > "legacy": "true"
> > },
> > {
> > "userId": "7452272EBA160D9AE040A8C048010EEB",
> > "smtpAddress": "dcampbell_at_knowledgemill.com",
> > "primary": "true",
> > "legacy": "false"
> > }
> > ]}
>
> This is bad, as it proves the natural notation is not being used in your case,
> otherwise, you would end up with just (no wrapping object present):
>
> [
> {
> "userId": "7452272EBA160D9AE040A8C048010EEB",
> "smtpAddress": "david.campbell_at_knowledgemill.com",
> "primary": "false",
> "legacy": "true"
> },
> {
> "userId": "7452272EBA160D9AE040A8C048010EEB",
> "smtpAddress": "dcampbell_at_knowledgemill.com",
> "primary": "true",
> "legacy": "false"
> }
> ]
>
> >
> > This looks good - I can see the array notation in the JSON.
> >
> > If I exercise this call (using JSON) where it returns a single element - I end up with a response shown below:
> >
> > {"UserEmailAddress": {
> > "userId": "7452272EBA160D9AE040A8C048230EEB",
> > "smtpAddress": "john_at_knowledgemill.com",
> > "primary": "true",
> > "legacy": "false"
> > }}
> >
> > This is bad - the single element is not coming back as an array.
> >
> > From my understanding this should have been rectified when using a NATURAL JSON notation. It does not work for me.
> >
> > I have also tried fixing the arrays specifically with the default MAPPED notation e.g.:
> >
> > JSONConfiguration.mapped().arrays( NAMES OF ARRAYS HERE).build()
>
> Could you please try with just:
>
> JSONConfiguration.mapped().arrays("UserEmailAddress").build();
>
> And let me know what happens with the single element array case?
>
> ~Jakub
>
> >
> > This also does not work.
> >
> > It appears that the ContextResolver is having no effect. However, I have confirmed that the Provider is being loaded on startup.
> >
> > Any help - much appreciated.
> >
> > Cheers.
> >
> > James
> >
>
> --
> Jakub Podlešák
> Software Engineer at SUN Microsystems And CZJUG Co-Leader
> http://blogs.sun.com/japod
>
>

-- 
Jakub Podlešák
Software Engineer at SUN Microsystems And CZJUG Co-Leader
http://blogs.sun.com/japod