Frage an json, jax-rs, jersey – Wie kann man JSON / JAXB von Jersey für die Serialisierung wiederverwenden?

28

Ich habe einen JAX-RS-REST-Dienst mit Jersey implementiert. Eine der coolen Eigenschaften von JAX-RS / Jersey ist, wie leicht ein POJO in einen REST-Service umgewandelt werden kann, indem einfach ein paar Java-Annotationen eingestreut werden.

Jetzt möchte ich diese coole JSON-fähige Funktion für Nicht-REST-Zwecke nutzen können. Ich würde gerne in der Lage sein, einige dieser Objekte einfach als JSON-Text auf die Festplatte zu serialisieren. Hier ist ein Beispiel für ein JAXB-Objekt, das ich serialisieren möchte:

@XmlRootElement(name = "user")
public class UserInfoImpl implements UserInfo {

    public UserInfoImpl() {} 

    public UserInfoImpl(String user, String details) {
        this.user = user;
        this.details = details;
    }

    public String getUser() { return user; }
    public void setUser(String user) { this.user = user; }

    public String getDetails() { return details; }
    public void setDetails(String details) { this.details = details; }

    private String user;
    private String details;
}

Jersey kann eine davon ohne zusätzliche Informationen in Json verwandeln. Ich frage mich, ob Jersey diese Funktionalität in der API für Bedürfnisse wie meine verfügbar gemacht hat. Ich hatte bisher kein Glück, es zu finden ...

Vielen Dank!

UPDATE 2009-07-09: Ich habe gelernt, dass ich das Provider-Objekt dazu verwenden kannfast mach genau das was ich will:

  @Context Providers ps;
  MessageBodyWriter uw = ps.getMessageBodyWriter(UserInfoImpl.class, UserInfoImpl.class, new Annotation[0], MediaType.APPLICATION_JSON_TYPE);

  uw.writeTo(....)

... Dies schreibt das Objekt als json in einen beliebigen Ausgabestream, was für mich perfekt wäre, aber ich kann das Providers-Objekt nur mit @Context von einem @Component-Objekt abrufen. Weiß jemand, wie er von einem normalen, nicht kommentierten POJO darauf zugreifen kann? Vielen Dank!

Ich versuche auch, Informationen darüber zu finden, aber ich habe nach etwas gesucht, das nur Javax. * / Java. * - APIs verwendet der JEE6 RI Archimedes Trajano
Ich kann auch eine Klasse zum Booten aufrufen. Archimedes Trajano

Deine Antwort

7   die antwort
5
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);
1

rlichen JSON-Objekte für Sie erstellen. Sie müssen die folgenden Abhängigkeiten einbeziehen (Sie können Bundle verwenden, dies führt jedoch zu Problemen, wenn Sie Weld zum Testen verwenden):

    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.12</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.12</version>
    </dependency>

Von dort aus können Sie eine mit JAXB-Anmerkungen versehene Klasse erstellen. Folgendes ist ein Beispiel:

@XmlRootElement
public class TextMessage {
private String text;
    public String getText() { return text; }
    public void setText(String s) { this.text = text; }
}

Dann können Sie den folgenden Komponententest erstellen:

    TextMessage textMessage = new TextMessage();
    textMessage.setText("hello");
    textMessage.setUuid(UUID.randomUUID());

    // Jersey specific start
    final Providers ps = new Client().getProviders();
    // Jersey specific end
    final MultivaluedMap<String, Object> responseHeaders = new MultivaluedMap<String, Object>() {

        @Override
        public void add(final String key, final Object value) {
        }

        @Override
        public void clear() {
        }

        @Override
        public boolean containsKey(final Object key) {
            return false;
        }

        @Override
        public boolean containsValue(final Object value) {
            return false;
        }

        @Override
        public Set<java.util.Map.Entry<String, List<Object>>> entrySet() {
            return null;
        }

        @Override
        public List<Object> get(final Object key) {
            return null;
        }

        @Override
        public Object getFirst(final String key) {
            return null;
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public Set<String> keySet() {
            return null;
        }

        @Override
        public List<Object> put(final String key, final List<Object> value) {
            return null;
        }

        @Override
        public void putAll(
                final Map<? extends String, ? extends List<Object>> m) {
        }

        @Override
        public void putSingle(final String key, final Object value) {
        }

        @Override
        public List<Object> remove(final Object key) {
            return null;
        }

        @Override
        public int size() {
            return 0;
        }

        @Override
        public Collection<List<Object>> values() {
            return null;
        }
    };

    final MessageBodyWriter<TextMessage> messageBodyWriter = ps
            .getMessageBodyWriter(TextMessage.class, TextMessage.class,
                    new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Assert.assertNotNull(messageBodyWriter);

    messageBodyWriter.writeTo(textMessage, TextMessage.class,
            TextMessage.class, new Annotation[0],
            MediaType.APPLICATION_JSON_TYPE, responseHeaders, baos);
    final String jsonString = new String(baos.toByteArray());
    Assert.assertTrue(jsonString.contains("\"text\":\"hello\""));

Der Vorteil dieses Ansatzes besteht darin, dass alles innerhalb der JEE6-API bleibt. Es werden keine externen Bibliotheken ausdrücklich benötigt, außer zum Testen und Abrufen der Anbieter. Sie müssen jedoch eine Implementierung von MultivaluedMap erstellen, da der Standard nichts enthält und wir ihn nicht verwenden. Eskann Seien Sie auch langsamer als GSON und viel komplizierter als nötig.

6

Zuordnen von Objekten zu JSON (unter Verwendung von Jackson):

http://ondra.zizka.cz/stranky/programovani/java/jaxb-json-jackson-howto.texy

1

vollständig darauf konzentriert, eine Standardmethode zum Implementieren des Endpunkts für den REST-Service bereitzustellen, bleiben die Fragen der Serialisierung der Nutzlast anderen Standards überlassen.

Ich denke, wenn sie die Objekt-Serialisierung in den JAX-RS-Standard aufnehmen würden, würde dies schnell zu einem großen Biest mit mehreren Köpfen, das schwer zu implementieren wäre und einen Teil seines Fokus verlieren würde.

Ich weiß zu schätzen, wie konzentriert Jersey darauf ist, saubere und einfach zu verwendende REST-Endpunkte bereitzustellen. In meinem Fall habe ich gerade ein übergeordnetes Objekt untergeordnet, in dem alle JAXB-Installationsanweisungen enthalten sind, sodass die Zuordnung von Objekten zwischen Binär- und XML-Code sehr einfach ist.

Ich glaube nicht, dass ich sehr klar war. Jersey übersetzt JAXB-Objekte bereits in JSON. Ich bin nicht auf der Suche nach Jersey, um "Serialisierungs" -Unterstützung hinzuzufügen, sondern um Zugriff auf die Provider-Funktionalität zu erhalten, die es bereits für mich hatbesitzen Serialisierungscode. Ich werde meine Frage aktualisieren, um Klarheit zu schaffen. Vielen Dank! ctwomey
19

je nachdem, ob Sie mapped (), badgerfish () oder natural () verwenden. Natürlich ist normalerweise das, was die Leute wollen. Und das wird mit dem sehr guten (und sehr schnellen) eigenständigen Jackson-JSON-Prozessor umgesetzt, der meiner Meinung nach von Object-> JAXB-> JSON stammt. Jackson stellt jedoch auch einen eigenen JAX-RS-Provider zur Verfügung, um direkt auf Object-> JSON zuzugreifen.

Sie fügten sogar Unterstützung für JAXB-Annotationen hinzu. Schau es dir an

http://wiki.fasterxml.com/JacksonJAXBAnnotations

Ich denke, das ist letztendlich das, wonach du suchst. Jackson verarbeitet Object <-> JSON ... Jersey erledigt nur die Anrufe für Sie

jackson.codehaus.org für jackson project home Andy O
Danke, Andy. Das hört sich in der Tat so an, wie ich es suche. Ich möchte einfach keine unnötigen zusätzlichen Abhängigkeiten hinzufügen. Vielen Dank! ctwomey
Stellen Sie sich das so vor: Sie benötigen eine Bibliothek für die XML-Serialisierung (JAXB, XStream oder so). Sie benötigen eine JSON-Bibliothek für JSON: JAXB stellt sie nicht zur Verfügung. Jersey versendet es auch an eine Bibliothek. Die Frage ist also eher, welche Bibliothek (en) hinzugefügt werden sollen. nicht, ob Sie etwas hinzufügen müssen. Jackson (oder json-tools, gson) kann das also problemlos. Und JAX-RS-Anbieter sind im Grunde genommen nur Dispatcher, die mit Medientypen arbeiten, die zu präsentierende "Ansicht" auswählen (json, xml, ...) und dann die entsprechende Bibliothek aufrufen. StaxMan
3

XML. Das Hauptproblem ist, dass JAXB keine leeren Arrays unterstützt. Also, wenn Sie so etwas serialisieren ...

List myArray = new ArrayList();

... um über Jaxb-Anottationen zu jsonen, werden alle Ihre leeren Arrays zu Null anstelle von [].

Um dies zu lösen, können Sie Ihre Pojos einfach direkt über jackson zu json serialisieren.

Schauen Sie sich dies in der Bedienungsanleitung von Jersey an:http://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959

Dies ist die beste Möglichkeit, den Jackson-Provider ohne JAXB zu verwenden. Darüber hinaus können Sie immer die neueste Version von jackson verwenden, indem Sie jackson-all-x.y.z-jar aus dem Internet herunterladen.

Diese Methode wird Ihre Jaxb-Anmerkungen nicht stören, daher würde ich vorschlagen, es einmal zu versuchen!

0

aber es hätte sich als sinnvoll erwiesen, JSON-Unterstützung für POJOs als Standardausrüstung zu fordern. Es macht keinen Sinn, JSON-Bezeichner mit Sonderzeichen zu versehen, wenn Ihre Implementierung JSON ist und Ihr Client eine JavaScript-RIA ist.

Auch nicht, dass Java Beans KEINE POJOs sind. Ich möchte so etwas auf der äußeren Oberfläche meiner Webschicht verwenden:

public class Model
{
   @Property height;
   @Property weight;
   @Property age;
}

Kein Standardkonstruktor, kein Get- / Setter-Rauschen, nur ein POJO mit eigenen Anmerkungen.

Ich glaube nicht, dass dies ein JAXB-Fehler ist: JAXB ist eine API für XML, nicht für andere Formate. Aber die Frage ist dann, ob die JAXB-API gebogen werden sollte, um für andere Formate zu funktionieren - wenn ja, sind Workarounds erforderlich. XML! = JSON. Übrigens: Jackson, das bereits erwähnt wurde, erlaubt die Verwendung von Nicht-Bean-POJOs. kann Felder oder Getter / Setter verwenden, echte Konstruktoren verwenden und so weiter. JAXB-Anmerkungen können als zusätzliche optionale Informationen verwendet werden, wenn der Benutzer dies wirklich wünscht. Das braucht sie aber nicht. StaxMan

Verwandte Fragen