consume - ¿Cómo reutilizar JSON/JAXB de Jersey para la serialización?
return json java rest (7)
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
Tengo un servicio REST JAX-RS implementado usando 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 rociando algunas anotaciones de Java ... incluyendo un mecanismo trivialmente sencillo para traducir los POJO a JSON, usando las 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 : Aprendí que puedo usar el objeto de los Proveedores para hacer casi 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 Proveedores utilizando @Context desde un objeto @Component. ¿Alguien sabe cómo acceder a él desde un POJO regular y sin anotaciones? ¡Gracias!
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 comentada 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. También puede ser más lento que GSON y mucho más complicado de lo necesario.
Debido a 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.
Entiendo las vistas XML, pero habría mostrado cierta previsión para requerir soporte JSON para POJO como equipo estándar. Tener que manipular 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 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.
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 implementó 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
Las anotaciones JAXB funcionan bien cuando se serializa a XML. El problema principal es que JAXB no admite matrices vacías. Así que cuando se serializa 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.
Mire esto en la guía de 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-xyz-jar desde su web.
¡Este método no interferirá con sus anotaciones jaxb, por lo que sugeriría que lo intente!
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);