Pregunta sobre jax-rs, json, jersey – ¿Cómo reutilizar JSON / JAXB de Jersey para la serialización?

28

Tengo un servicio REST JAX-RS implementado utilizando Jersey. Una de las características interesantes de JAX-RS / Jersey es la facilidad con la que un POJO se puede convertir en un servicio REST, simplemente mediante el riego de algunas anotaciones de Java ... incluido un mecanismo trivialmente sencillo para traducir los POJO a JSON, utilizando anotaciones de JAXB.

Ahora, me gustaría poder aprovechar esta genial funcionalidad de JSON para propósitos no REST - Me encantaría poder simplemente serializar algunos de estos objetos en el disco, como texto JSON. Aquí hay un ejemplo de objeto JAXB que me gustaría serializar:

@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 puede convertir uno de estos en json sin información adicional. Me pregunto si Jersey ha expuesto esta funcionalidad en la API para necesidades como la mía. No he tenido la suerte de encontrarlo hasta ahora ...

¡Gracias!

ACTUALIZACIÓN 2009-07-09: He aprendido que puedo usar el objeto Proveedores paracasi hacer exactamente lo que quiero:

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

  uw.writeTo(....)

... Esto escribe el objeto como json en cualquier flujo de salida, lo que sería perfecto para mí, pero solo puedo acceder al objeto Providers utilizando @Context desde un objeto @Component. ¿Alguien sabe cómo acceder a él desde un POJO regular y sin anotaciones? ¡Gracias!

También estoy bien con llamar a una clase para bootstrapping. Archimedes Trajano
También estoy tratando de encontrar información sobre esto, pero estaba buscando algo que solo usara javax. * / Java. * Solo API (no me importa agregar bibliotecas adicionales para las pruebas de JUnit, pero espero que estén presentes en el JEE6 RI Archimedes Trajano

Tu respuesta

7   la respuesta
3

Las anotaciones JAXB funcionan bien cuando se serializa a XML. El problema principal es que JAXB no admite matrices vacías. Entonces cuando serializamos algo como esto ...

List myArray = new ArrayList();

... a json vía jaxb anottations todas sus matrices vacías se vuelven nulas en lugar de [].

Para resolver esto puedes simplemente serializar tus pojos directamente a json a través de jackson.

Eche un vistazo a esto en la guía del usuario de Jersey:http://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959

Esta es la mejor manera de usar el proveedor de Jackson sin JAXB. Además, siempre puedes usar la última versión de jackson descargando jackson-all-x.y.z-jar desde su web.

¡Este método no interferirá con sus anotaciones jaxb, por lo que sugeriría que lo intente!

1

Dado que Jersey es una implementación de referencia de JAX-RS, JAX-RS se enfoca completamente en proporcionar una manera estándar de implementar el punto final para el servicio REST, los problemas de la serialización de la carga útil se dejan a otros estándares.

Creo que si incluyeran la serialización de objetos en el estándar JAX-RS, rápidamente se convertiría en una gran bestia con múltiples cabezas que sería difícil de implementar y perdería parte de su enfoque.

Aprecio lo concentrada que está Jersey en ofrecer puntos finales REST limpios y fáciles de usar. En mi caso, acabo de subclasificar a un padre que tiene todas las tuberías de JAXB, así que ordenar objetos entre binario y XML es muy limpio.

No creo que fuera muy claro. La cuestión es que Jersey ya traduce los objetos JAXB a JSON. No estoy buscando que Jersey agregue soporte de "serialización", sino más bien para obtener acceso a la funcionalidad de Proveedor que ya tiene para mipropio Código de serialización. Voy a actualizar mi pregunta para añadir algo de claridad. ¡Gracias! ctwomey
19

Jersey usa un par de marcos diferentes dependiendo de si usas la notación mapeada (), el pez tejón () o la natural (). Lo natural es lo que la gente quiere. Y eso se implementa utilizando el procesador Jackson JSON independiente muy bueno (y muy rápido), creo, que va desde Object-> JAXB-> JSON. Sin embargo, Jackson también proporciona su propio proveedor JAX-RS para ir directamente a Object-> JSON.

De hecho, incluso agregaron soporte para las anotaciones JAXB. Mira esto

http://wiki.fasterxml.com/JacksonJAXBAnnotations

Creo que en última instancia eso es lo que estás buscando. Jackson realiza el procesamiento de objetos <-> JSON ... Jersey simplemente realiza las llamadas por usted

Bueno, piénselo de esta manera: necesita una biblioteca para la serialización XML (JAXB, XStream o similar). Necesita una biblioteca JSON para JSON: JAXB no la proporciona; Jersey también lo envía a una biblioteca. Entonces la pregunta es más bien qué lib (s) agregar; No si necesitas agregar algo. Así que Jackson (o json-tools, gson) puede hacerlo fácilmente. Y los proveedores de JAX-RS son realmente poco más que los despachadores que operan en tipos de medios, seleccionando qué "vista" presentar (json, xml, ...), y luego llamando a la biblioteca correspondiente. StaxMan
Gracias, Andy. Esto realmente suena como lo que estoy buscando. Simplemente no quiero agregar dependencias adicionales innecesarias. ¡Gracias! ctwomey
jackson.codehaus.org para jackson project home Andy O
0

Entiendo las vistas XML, pero habría sido un poco prospectivo requerir el soporte JSON para POJO como equipo estándar. Tener que identificar los identificadores JSON con caracteres especiales no tiene sentido si su implementación es JSON y su cliente es un RIA de JavaScript.

Además, no es que los Beans de Java NO sean POJOs. Me gustaría usar algo como esto en la superficie exterior de mi nivel web:

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

Ningún constructor predeterminado, ningún ruido de captador / configurador, solo un POJO con mis propias anotaciones.

No creo que esto sea un error de JAXB: JAXB es API para XML, no para otros formatos. Pero la pregunta entonces es si la API de JAXB debería estar doblada para trabajar con otros formatos; de ser así, se necesitan soluciones alternativas. XML! = JSON. Btw: Jackson, que ya se mencionó, permite el uso de POJO no Bean; puede usar campos o getters / setters, usar constructores reales reales y así sucesivamente. Puede usar las anotaciones JAXB como información opcional adicional si el usuario realmente quiere eso. Pero eso no los necesita. StaxMan
1

Con un poco de arranque específico de Jersey, puedes usarlo para crear los objetos JSON necesarios para ti. Debe incluir las siguientes dependencias (puede usar el paquete, pero causará problemas si está utilizando Weld para pruebas):

    <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>

Desde allí puede crear una clase anotada JAXB. Lo siguiente es un ejemplo:

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

Luego puedes crear la siguiente prueba unitaria:

    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\""));

La ventaja de este enfoque es que mantiene todo dentro de la API JEE6, no se necesitan bibliotecas externas explícitamente, excepto para probar y obtener los proveedores. Sin embargo, debe crear una implementación de MultivaluedMap ya que el estándar no incluye nada y en realidad no lo usamos. Esomayo también ser más lento que GSON, y mucho más complicado de lo necesario.

5
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);
6

Aquí hay un breve ejemplo simple del uso de JAXB para asignar objetos a JSON (usando Jackson):

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

Preguntas relacionadas