简体   繁体   中英

Jersey/JAX-RS: Return a Map as XML/JSON

It's not so obvious how to return a Map as an XML/JSON document using the Jersey/JAX-RS framework. It already has support for List s, but when it comes to Map s, there is no MessageBodyWriter . And even if I were to embed the Ma into a wrapper class, there is no map type in XML schema.

Any practical advice on how to marshal a Map into an XML/JSON document in Jersey?

I know its very late to reply, but I'm hoping it will help somebody someday :) The easiest and quickest fix I applied is

@GET
@Path("/{messageId}")
@Produces(MediaType.APPLICATION_JSON)
public Response getMessage(@PathParam("messageId") long id) {
    Map<String, String> map = new HashMap<>();
    map.put("1", "abc");
    map.put("2", "def");
    map.put("3", "ghi");

    return Response.status(Status.OK).entity(map).build();
}

Output: { "1": "abc", "2": "def", "3": "ghi" }

This should definitely help you solve your trouble.

It is very easy to do this in Java EE 7.

The REST Resource class:

package com.mycompany.maptojson.rest;

import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.enterprise.context.RequestScoped;

@Path("maps")
@RequestScoped
public class MapToJson {

    @GET
    @Produces("application/json")
    public Map getJson() {
       Map<String, String> theMap = new HashMap<>();
       theMap.put("foo", "bar");
       return theMap;
    }
}

The Application :

package com.mycompany.maptojson.rest;

import java.util.Set;
import javax.ws.rs.core.Application;

@javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> resources = new java.util.HashSet<>();
        // following code can be used to customize Jersey 2.0 JSON provider:
        try {
            Class jsonProvider = Class.forName("org.glassfish.jersey.jackson.JacksonFeature");
            // Class jsonProvider = Class.forName("org.glassfish.jersey.moxy.json.MoxyJsonFeature");
            // Class jsonProvider = Class.forName("org.glassfish.jersey.jettison.JettisonFeature");
            resources.add(jsonProvider);
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        addRestResourceClasses(resources);
        return resources;
    }

    private void addRestResourceClasses(Set<Class<?>> resources) {
        resources.add(com.mycompany.maptojson.rest.MapToJson.class);
    }
}

As you can see, you can configure different classes as jsonProvider :

Class.forName("org.glassfish.jersey.jackson.JacksonFeature");

or

Class.forName("org.glassfish.jersey.moxy.json.MoxyJsonFeature");

or

Class.forName("org.glassfish.jersey.jettison.JettisonFeature");

I know it's been a while already, but maybe someone will find it useful.

I am having a similar problem and to me it looks like, that only Jackson currently supports this sort of direct Map to JSON mapping.

In Jersey , it is as easy as returning the map from the resource method:

@Path("myResource")
public class MyResource {
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Map<String, String> getMap() {
      Map<String, String> map = new HashMap<String, String>();
      map.put("some key", "some value");
      return map;
  }
}

and accessing it from the client as:

// ... (client initialization)
Map<String, String> map = client.target().path("myResource").request("application/json").get(Map.class);

With Jackson (as opposed to MOXy ), you need to register the JacksonFeature manually, eg in your javax.ws.rs.core.Application subclass (or ResourceConfig in Jersey ):

public class MyApp extends ResourceConfig {
  public MyApp() {
    super(MyResource.class, JacksonFeature.class);
  }
}

And be sure to have Jersey Jackson module on classpath. In maven, simply add:

<dependency>
  <groupId>org.glassfish.jersey.media</groupId>
  <artifactId>jersey-media-json-jackson</artifactId>
  <version>...</version>
</dependency>

without maven, it might be a bit more tricky to add all the dependencies. And that's all, this should work. At least with Jackson provider.

It did not work for me in Jettison and id does not work in MOXy yet (there's an issue open).

Hope this helps.

The solution that worked for me (Using jettison):

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getJson() {
    Map<String, String> testMap = new HashMap<>();
    testMap.put("Key1", "value1");
    testMap.put("key2", "value2");
    JSONObject obj = new JSONObject(testMap);

    return Response.status(200).entity(obj).build();
}

By default, Jersey uses MOXy XML/JSON provider. So if you want to use MOXy, you need to add separate adapter. The simple solution is, remove MOXy dependency from pom.xml and add Jackson dependency. Jackson will take care of everything.

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>{latest version}</version>
</dependency>

Sorry,I'm not sure why MOXy is the default provider in Jeresey.

public class BeanClass{
    private int duration, Id;
    private String description;
    private User user = new User();
    Map<String, String> map = new HashMap<>();
 }


@GET
@Produces({ MediaType.APPLICATION_JSON }) // , MediaType.APPLICATION_XML
public Response getAll() {
        List<BeanClass> lstBean = ...
        return Response.ok().entity(lstBean).build();
}

Thanks,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM