6

Using Jersey and Jackson to create a REST interface, how do I get List fields to be serialized as a list when there are 0 or 1 elements in them. For example:

@XmlRootElement(name="foo")
public class Foo {
  @XmlElement
  public List<Bar> getBars() {
    return this.bars;
  }
}

@Path("foo")
public FooResource {
  @GET
  public Foo getFoo() {
    return theFoo;
  }
}

When bars has no elements, the result serializes as null and when it contains a single element, it serializes as that element, not an array containing a single element. Is there a way to get these to always serialize as an array?

For reference, I'm using Jersey 1.10 and Jackson 1.9.2.

Qwerky
  • 18,217
  • 6
  • 44
  • 80
Brandon DuRette
  • 4,810
  • 5
  • 25
  • 31

4 Answers4

4

I am pretty sure that you are not actually using Jackson ("POJO" variant of JSON serialization), since Jackson would not convert single-element arrays or lists to anything else. So you are probably using one of legacy output methods (like jettison); meaning that if you configure system to use POJO mapping it should just work.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • You are correct, Jackson was not correctly configured. Is there a more explicit way to configure Jackson for use within Jersey besides adding 'org.codehaus.jackson.jaxrs' to the com.sun.jersey.config.property.packages init param? – Brandon DuRette Dec 06 '11 at 21:14
  • It is possible to explicitly register provider class from jax-rs jar (`JacksonJsonProvider`), using standard JAX-RS registration mechanism, see http://wiki.fasterxml.com/JacksonFAQ#JAX-RS (for example) for details. – StaxMan Dec 07 '11 at 06:25
3

I wrote a blog post ages ago about forcing Jersey to serialize single element arrays correctly, not sure if it's out-dated now (its from mid-2010!), but it might be of use.

Note the blog comment from Brill Pappin on the blog demonstrating a different approach which means upgrading the Jettison library that you are using.

In short you can write a custom JaxbContextResolver that looks a little like:

@Provider
@Component
public class JAXBContextResolver implements ContextResolver {

    private JAXBContext context;

    public JAXBContextResolver() throws Exception {
        MappedBuilder builder = JSONConfiguration.mapped();
        builder.arrays("invite");
        builder.rootUnwrapping(true);
        this.context = new JSONJAXBContext(builder.build(), Payload.class);
    }

    public JAXBContext getContext(Class objectType) {
        return (Payload.class.equals(objectType)) ? context : null;
    }
}

For clarity, my payload class looked a little like

@XmlRootElement(name = "response")
@XmlAccessorType(XmlAccessType.FIELD)
public class Payload {

    @XmlElement(name = "invite")
    List invites;

    ... etc.

Regarding stopping Jackson serializing bean properties as null, see my previous answer here, about using annotations to change that behaviour.

Community
  • 1
  • 1
Derek Troy-West
  • 2,469
  • 1
  • 24
  • 27
  • Ok. I've created a ContextResolver that uses reflection to change the serialization behavior of all the lists in my data beans. This still feels a bit too brute force for my taste. Still interested in a better way if there is one. – Brandon DuRette Nov 21 '11 at 20:44
  • Take a look at Brill Pappin's comment on my blog link from the answer, he describes a solution where you upgrade the version of Jettison that Jackson relies on.. – Derek Troy-West Nov 21 '11 at 22:23
  • Um, you probably mean "Jettison that Jersey depends on" (for one of JSON binding methods). Jackson does not depend on Jettison (or vice versa) – StaxMan Nov 24 '11 at 00:37
1

I managed to solve JSON array "bug" in recent Jersey json library (v1.14 Sep 2012). Secret ingredient is JSONConfiguration and ContextResolver magic. See my following post it has a full code example, customized ContextResolver and rest Application class might be somewhat fuzzy logic in first look.

How to serialize Java primitives using Jersey REST

Primitives and zero or single-element List array are properly serialized to JSON document.

Community
  • 1
  • 1
Whome
  • 10,181
  • 6
  • 53
  • 65
0

Yes, we also faced the same issue. Jackson cannot serialize list with 0 or single element to json array. So we tried to use Json's ObjectMapper to convert POJO object to String. It will serialize java List to json array irrespective of number of elements in List (0 or 1 or > 0). The code would look like :

 request = new ObjectMapper().writeValueAsString(pojo);

where request is of type Object. This will not affect response. You can give a try.