Frage

Ich versuche, einen sehr einfachen REST-Server zu erstellen. Ich habe nur ein Testverfahren, das eine Liste der Strings zurück. Hier ist der Code:


@GET
@Path("/test2")
public List test2(){
    List list=new Vector();
    list.add("a");
    list.add("b");
    return list;
}

Es gibt folgende Fehlermeldung:

SEVERE: A message body writer for Java type,
class java.util.Vector, and MIME media type,
application/octet-stream, was not found

Ich habe gehofft, JAXB hatte einen Standard für einfache Typen wie String Einstellung, Integer, etc. Ich denke nicht. Hier ist, was ich dachte:


<Strings>
  <String>a</String>
  <String>b</String>
</Strings>

Was ist der einfachste Weg, diese Methode funktioniert?

War es hilfreich?

Lösung

Ich habe @ LiorH Beispiel und erweiterte es an:


@XmlRootElement(name="List")
public class JaxbList<T>{
    protected List<T> list;

    public JaxbList(){}

    public JaxbList(List<T> list){
        this.list=list;
    }

    @XmlElement(name="Item")
    public List<T> getList(){
        return list;
    }
}

Beachten Sie, dass es Generika verwendet, so dass Sie es mit anderen Klassen als String verwenden können. Nun wird der Anwendungscode ist einfach:


    @GET
    @Path("/test2")
    public JaxbList test2(){
        List list=new Vector();
        list.add("a");
        list.add("b");
        return new JaxbList(list);
    }

Warum gibt es nicht diese einfache Klasse in dem JAXB-Paket? Wer sieht alles wie es anderswo?

Andere Tipps

@GET
@Path("/test2")
public Response test2(){
   List<String> list=new Vector<String>();
   list.add("a");
   list.add("b");

   final GenericEntity<List<String>> entity = new GenericEntity<List<String>>(list) { };
   return Response.ok().entity(entity).build();
}

Falls jemand von euch will eine Liste Wrapper für Listen Elemente von mehreren Klassen schreiben, enthält, und wollen einen individuellen XmlElement Namen geben nach dem Klassentyp ohne Schreiben X Wrapperklassen Sie die @XmlMixed Annotation nutzen könnten. so Namen JAXB die Elemente der Liste nach dem Wert der @XmlRootElement Dadurch. Wenn Dabei müssen Sie, welche Klassen angeben möglicherweise in der Liste sein könnte mit @XmlSeeAlso

Beispiel:

Mögliche Klassen in der Liste

@XmlRootElement(name="user")
public class User {/*...*/}

@XmlRootElement(name="entry")
public class LogEntry {/*...*/}

Wrapper-Klasse

@XmlRootElement(name="records")
@XmlSeeAlso({User.class, LogEntry.class})
public static class JaxbList<T>{

    protected List<T> records;

    public JaxbList(){}

    public JaxbList(List<T> list){
        this.records=list;
    }

    @XmlMixed 
    public List<T> getRecords(){
        return records;
    }
}

Beispiel:

List l = new List();
l.add(new User("userA"));
l.add(new LogEntry(new UserB()));


XStream xStream = new XStream();
String result = xStream.toXML(l);

Ergebnis:

<records>
    <user>...</user>
    <entry>...</entry>
</records>

Alternatevily Sie die XmlElement Namen direkt in der Wrapper-Klasse mit der @XmlElementRef Anmerkung angeben könnten

@XmlRootElement(name="records")
@XmlSeeAlso({User.class, LogEntry.class})
public static class JaxbList<T>{

    protected List<T> records;

    public JaxbList(){}

    public JaxbList(List<T> list){
        this.records=list;
    }

    @XmlElementRefs({
        @XmlElementRef(name="item", type=Object.class),
        @XmlElementRef(name="user", type=User.class),
        @XmlElementRef(name="entry", type=LogEntry.class)
    })
    public List<T> getRecords(){
        return records;
    }
}

Von einer persönlichen Blog Post es ist nicht notwendig, ein spezifisches JaxbList < T > Objekt zu erstellen.

ein Objekt mit einer Liste von Strings Unter der Annahme:

@XmlRootElement
public class ObjectWithList {

    private List<String> list;

    @XmlElementWrapper(name="MyList")
    @XmlElement
    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

}

Eine JAXB Rundreise:

public static void simpleExample() throws JAXBException {

    List<String> l = new ArrayList<String>();
    l.add("Somewhere");
    l.add("This and that");
    l.add("Something");

    // Object with list
    ObjectWithList owl = new ObjectWithList();
    owl.setList(l);

    JAXBContext jc = JAXBContext.newInstance(ObjectWithList.class);
    ObjectWithList retr = marshallUnmarshall(owl, jc);

    for (String s : retr.getList()) {
        System.out.println(s);
    } System.out.println(" ");

}

Erzeugt die folgenden:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<objectWithList>
    <MyList>
        <list>Somewhere</list>
        <list>This and that</list>
        <list>Something</list>
    </MyList>
</objectWithList>

Dies kann getan werden, VIEL einfacher mit wunderbar XStream Bibliothek. Kein Wrapper, keine Anmerkungen.

Ziel XML

<Strings>
  <String>a</String>
  <String>b</String>
</Strings>

Serialisierung

(String alias kann mit Klein string Tag vermieden werden, aber ich verwenden OPs Code)

List <String> list = new ArrayList <String>();
list.add("a");
list.add("b");

XStream xStream = new XStream();
xStream.alias("Strings", List.class);
xStream.alias("String", String.class);
String result = xStream.toXML(list);

Deserialisierung

Deserialisierung in Arraylist

XStream xStream = new XStream();
xStream.alias("Strings", ArrayList.class);
xStream.alias("String", String.class);
xStream.addImplicitArray(ArrayList.class, "elementData");
List <String> result = (List <String>)xStream.fromXML(file);

Deserialisierung in String []

XStream xStream = new XStream();
xStream.alias("Strings", String[].class);
xStream.alias("String", String.class);
String[] result = (String[])xStream.fromXML(file);

Hinweis, dass XStream Instanz threadsicher und vorkonfiguriert werden können, Kodemenge zu Einzeiler schrumpft.

Xstream kann auch als Standard-Serialisierung Mechanismus für die JAX-RS-Dienst verwendet werden. Beispiel Verstopfungs XStream in Jersey finden Sie hier zu finden

mir dieses Muster ein paar Mal begegnet ist, fand ich, dass der einfachste Weg ist, eine innere Klasse mit JAXB Anmerkungen zu definieren. (Sowieso, werden Sie wahrscheinlich die Root-Tag-Namen definieren mögen)

, damit Ihr Code wie folgt aussehen würde

@GET
@Path("/test2")
public Object test2(){
   MyResourceWrapper wrapper = new MyResourceWrapper();
   wrapper .add("a");
   wrapper .add("b");
   return wrapper ;
}

@XmlRootElement(name="MyResource")
private static class MyResourceWrapper {
       @XmlElement(name="Item")
       List<String> list=new ArrayList<String>();
       MyResourceWrapper (){}

       public void add(String s){ list.add(s);}
 }

Wenn Sie mit javax.rs (JAX-RS) arbeiten ich Response-Objekt mit dem Wrapper als Einheit gesetzt zurückkehren würde

Endlich habe ich es gelöst JacksonJaxbJsonProvider mit Es erfordert einige Änderungen in Ihrem Frühling context.xml und Maven pom.xml

In Ihrem Frühling context.xml JacksonJaxbJsonProvider zum <jaxrs:server> hinzufügen:

<jaxrs:server id="restService" address="/resource">
    <jaxrs:providers>
        <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/>
    </jaxrs:providers>
</jaxrs:server>

In Ihrem Maven pom.xml add:

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-jaxrs</artifactId>
    <version>1.9.0</version>
</dependency>

Benutzer1 Beispiel gut für mich gearbeitet. Aber, als Warnung, wird es nicht mit etwas anderem als einfachen String / Integer-Typen arbeiten, wenn Sie eine @XmlSeeAlso Anmerkung hinzufügen:

@XmlRootElement(name = "List")
@XmlSeeAlso(MovieTicket.class)
public class MovieTicketList {
    protected List<MovieTicket> list;

Dies funktioniert OK, obwohl es mich daran hindert, eine einzige allgemeine Liste Klasse über meine gesamte Anwendung. Es könnte auch erklären, warum diese scheinbar offensichtliche Klasse nicht in dem JAXB-Paket vorhanden ist.

Stellen Sie sicher, @XmlSeeAlso Tag mit Ihren spezifischen Klassen innerhalb JaxbList verwendet hinzuzufügen. Es ist sehr wichtig, sonst wirft es HttpMessageNotWritableException

Ich würde gesparte Zeit habe, wenn ich gefunden Resteasy Jackson Provider früher.

Fügen Sie einfach die Resteasy Jackson JAR Provider . Keine Einheit Wrapper. Keine XML-Annotationen. Keine benutzerdefinierten Nachrichtentext Schriftsteller.

Wenn Sie Maven im Trikot Projekt verwenden hinzufügen unten in pom.xml und Aktualisierung Projektabhängigkeiten, so dass jaxb der Lage ist, Modellklasse zu erkennen und konvertieren Liste Medientyp Anwendung XML:

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.2.11</version>
</dependency>

Für eine allgemeinere Lösung für JAXB-XML-Serialisierung alle Top-Level-Liste, die benötigt nur 1 neue Klasse geschrieben werden, um die Lösung in dieser Frage gegeben Check-out:

Ist es möglich, programmatisch JAXB zu konfigurieren?

public class Wrapper<T> {

private List<T> items = new ArrayList<T>();

@XmlAnyElement(lax=true)
public List<T> getItems() {
    return items;
}

}

//JAXBContext is thread safe and so create it in constructor or 
//setter or wherever:
... 
JAXBContext jc = JAXBContext.newInstance(Wrapper.class, clazz);
... 

public String marshal(List<T> things, Class clazz) {

  //configure JAXB and marshaller     
  Marshaller m = jc.createMarshaller();
  m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

  //Create wrapper based on generic list of objects
  Wrapper<T> wrapper = new Wrapper<T>(things);
  JAXBElement<Wrapper> wrapperJAXBElement = new JAXBElement<Wrapper>(new QName(clazz.getSimpleName().toLowerCase()+"s"), Wrapper.class, wrapper);

  StringWriter result = new StringWriter();
  //marshal!
  m.marshal(wrapperJAXBElement, result);

  return result.toString();

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top