Jersey: Return a list of strings

2019-01-08 23:26发布

I try to return a list of Strings in Jersey as JSON and XML. I thought this would be trivial.

My first try was to write something like this

@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Path("/bar")
public List<String> get() {
    return dao.get();
}

and I expected an output similiar to this: ["string1", ..., "stringN] unfortunately I got this:

com.sun.jersey.api.MessageException: A message body writer for Java class java.util.LinkedList, and Java type java.util.List<java.lang.String>, and MIME media type application/json was not found 

Then I wrote a wrapper StringList for List

@XmlRootElement
public class StringList {

    private List<String> data;

    public StringList() {
    }

    public StringList(List<String> data) {
        this.data = data;
    }

    public List<String> getData() {
        return data;
    }

    public void setData(List<String> data) {
        this.data = data;
    }
}

and modified the facade to

@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Path("/foo")
public StringList stringlist() {
    return new StringList(sl());
}

Which works great for Lists with more items than 1.

{"data":["foo","bar"]}

Unfortunately I get two unexepected results for one or zero elements

{"data": "just one"} // for one element i would expect {"data": ["just one"]}

null // for no elements i would expect {"data": []}

Am I doing something completly wrong? How can I fix this?

6条回答
forever°为你锁心
2楼-- · 2019-01-08 23:47

In order to convince Jersey to output lists the way you want to, you need to provide an own ContextResolver:

@Provider
public class JaxbContentResolver implements ContextResolver<JAXBContext> {

    private Log log = LogFactory.getLog(getClass());
    private JAXBContext context;

    public JaxbContentResolver() throws JAXBException {
        Class[] types = {StringList.class};
        context = new JSONJAXBContext(JSONConfiguration.mapped().rootUnwrapping(true).arrays("data").build(), types);
    }

    @Override
    public JAXBContext getContext(Class<?> objectType) {
        log.trace("Entering Test-getContext for type: " + objectType.getSimpleName());
        return context;
    }
}

This way lists will appear the way you want them to.

NOTE: One downside of this approach is that you need to maintain one additional spot in your code; in case you want to add another (list wrapper) class to your REST interface, you need to remember to go to above code and add that class in your ContextResolver...

查看更多
我命由我不由天
3楼-- · 2019-01-08 23:48

My solution to this was a wrapper class (found it somewhere). It works now. I don't understand the thoughts behind not supporting javas List class as a root element. Perhaps it has to do with some json specification / best practice i'm not aware of.

But for now im using this:

public class Houses {
    private List<String> houses;

    // Needed for jersey
    public Houses() { }

    public Houses(List<String> houses) {
        this.houses = houses;
    }

    public void setHouses(List<String> houses) {
        this.houses = houses;
    }

    public List<String> getHouses() {
        return this.houses;
    }
}
查看更多
该账号已被封号
4楼-- · 2019-01-08 23:49

You could use javax.ws.rs.core.GenericEntity:

@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("/foo")
public GenericEntity<List<String>> stringlist()
{
  List<String> list = Arrays.asList("test", "as");

  return new GenericEntity<List<String>>(list) {};
}
查看更多
冷血范
5楼-- · 2019-01-08 23:53

Okay, I could fix it by searching the samples

This does work, but it can only be used for JSON and not for XML

@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("/get")
public JSONArray get() {;
    return new JSONArray(dao.getStringList());
}

Fixes problem, but is there also a generic approach?

查看更多
一纸荒年 Trace。
6楼-- · 2019-01-08 23:54

In addition to the provided answers, if you still get MessageBodyWriter not found, try adding a dependency such as:

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-moxy</artifactId>
    </dependency>
查看更多
萌系小妹纸
7楼-- · 2019-01-09 00:06

You need to use the alternative JSON configuration JSONConfiguration.natural().

Best you create your own ContextResolver using that alternative configuration as a provider and tell it which classes it is responsible for.

I am unaware of a method to use the alternative configuration globally in another way.

查看更多
登录 后发表回答