JAX-RS, Map<String,String> to JSON without the overhead?

14,391

Solution 1

Simplest way would be using List<Pair> instead where Pair is just a Javabean with two properties.

Solution 2

"JAXB spec defines a special handling for Map when it's used as a property of a bean."

In light of that, I don't think there is much you can do (currently) except, perhaps, to write your own MessageBodyWriter (https://jsr311.dev.java.net/nonav/javadoc/javax/ws/rs/ext/MessageBodyWriter.html)

Solution 3

If you don't use JAXB annotated objects, but simple POJO's, you can get the correct behaviour by simply enabling the POJO mapping feature, together with the Jackson JSON library.

So in web.xml, if you're using the filter (similar for servlet), your configuration should be:

<filter>
  <filter-name>Jersey</filter-name>
  <filter-class>...</filter-class>
  <init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
  </init-param>
</filter>

And just depend on the jersey-json dependency in your maven config, or download it from the website and put jackson in your classpath. See also this answer and this answer, and this blog post. And why on earth this is not standard behaviour I do not know.

Share:
14,391
Admin
Author by

Admin

Updated on June 12, 2022

Comments

  • Admin
    Admin almost 2 years

    I'm using JAX-RS to create restful webservices in Java. I am getting to much overhead in the produced JSON.

    Data class:

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Test {
    
        private Map<String,String> data;
    
        Test() {}
    
        public Test(Map<String,String> data) {
            this.data = data;
        }
    
        public Map<String, String> getData() {
            return data;
        }
    }
    

    Service:

    @GET
    @Path("/test")
    @Produces("application/json; charset=UTF-8;")
    public Test test() {
       Map<String,String> map = new HashMap<String,String>();
       map.put("foo", "bar");
       map.put("bingo", "bongo");
       return new Test(map);
    }
    

    Produces:

    {"data":{"entry":[{"key":"foo","value":"bar"},{"key":"bingo","value":"bongo"}]}}
    

    I would like it to produce:

    {"data":{"foo":"bar","bingo":"bongo"}}
    

    What is the simplest way to achive this? I am free to redifine my data class but I can't know in advance the keys or size of the map.