webentwicklung-frage-antwort-db.com.de

Jersey: Gibt eine Liste von Zeichenfolgen zurück

Ich versuche, eine Liste von Strings in Jersey als JSON und XML zurückzugeben. Ich dachte, das wäre trivial.

Mein erster Versuch war, so etwas zu schreiben

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

und ich erwartete eine Ausgabe, die der folgenden ähnelt: ["string1", ..., "stringN] leider habe ich Folgendes erhalten:

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 

Dann schrieb ich eine Wrapper StringList für 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;
    }
}

und modifizierte die Fassade auf

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

Was gut für Listen mit mehr als 1 Elementen geeignet ist.

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

Leider erhalte ich zwei nicht-ermittelte Ergebnisse für ein oder null Elemente

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

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

Mache ich etwas völlig falsch? Wie kann ich das beheben?

17
user524824

Sie könnten javax.ws.rs.core.GenericEntity verwenden:

@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) {};
}
6
sdorra

Okay, ich könnte es reparieren, indem ich die Proben durchsuche

Dies funktioniert zwar, kann aber nur für JSON und nicht für XML verwendet werden

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

Behebt das Problem, aber gibt es auch einen generischen Ansatz?

8
user524824

Um Jersey zu überzeugen, Listen so auszugeben, wie Sie es möchten, müssen Sie einen eigenen ContextResolver bereitstellen:

@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;
    }
}

Auf diese Weise werden Listen so angezeigt, wie Sie es möchten.

ANMERKUNG: Ein Nachteil dieses Ansatzes ist, dass Sie eine zusätzliche Stelle in Ihrem Code beibehalten müssen. Falls Sie Ihrer REST -Oberfläche eine weitere (Listen-Wrapper-) Klasse hinzufügen möchten, müssen Sie daran denken, zum obigen Code zu gehen und diese Klasse in Ihrem ContextResolver hinzuzufügen ...

1
Julius Blank

Wenn Sie zusätzlich zu den bereitgestellten Antworten noch MessageBodyWriter not found erhalten, fügen Sie eine Abhängigkeit hinzu, beispielsweise:

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-moxy</artifactId>
    </dependency>
0
Skylar Saveland

Meine Lösung dafür war eine Wrapper-Klasse (fand sie irgendwo). Es funktioniert jetzt. Ich verstehe nicht die Gedanken, die javas List nicht als Wurzelelement unterstützen. Vielleicht hat es etwas mit json-Spezifikationen/Best Practices zu tun, von denen ich keine Kenntnis habe.

Aber im Moment nutze ich das:

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;
    }
}
0
sigi

Sie müssen die alternative JSON-Konfiguration JSONConfiguration.natural() verwenden.

Am besten erstellen Sie Ihre eigene ContextResolver, indem Sie diese alternative Konfiguration als Provider verwenden und angeben, für welche Klassen sie verantwortlich ist.

Mir ist keine Methode bekannt, die alternative Konfiguration global auf andere Weise zu verwenden.

0
someone