java - Serialización de nulos y cadenas vacías en JSON dinámico
serialization jaxb (1)
Hay cosas que quizás quieras probar.
Primero, intente utilizar @XmlElement(nillable=true)
lugar de la anotación XmlNullPolicy
o establezca el parámetro emptyNodeRepresentsNull
.
En segundo lugar, es posible que desee escribir su propio XmlAdapter
que hará más o menos lo mismo: unmarshall empty string to null. La principal diferencia es que también puede configurar manualmente qué campos se desmarcarán con su adaptador y cuáles no, por lo tanto, conservará el comportamiento actual. Consulte esta answer de Blaise Doughan para ver cómo XmlAdapter
un XmlAdapter
personalizado a su configuración.
Tercero, que yo sepa, Jackson no tiene este problema. Vea esta respuesta de esta página wiki sobre cómo configurar un deserializador personalizado para un campo en caso de que lo haga.
Tengo este contenido JSON:
{"color":null}
Y quiero hacer que estos objetos Java salgan de él (y viceversa):
Container
|- List<Entry> entries
|- Entry
|- String key = "color"
|- String value = null
Mi solución actual siempre deserializa "color":null
a una cadena vacía . Encontré otras soluciones, que en su lugar deserializarán String null
o vacío para null
.
¿Cómo puedo obtener MOXy (o cualquier otra implementación de jaxb) para deserializar null
como cadenas vacías y vacías para vaciar Cadenas?
Estoy usando este código:
import java.io.ByteArrayOutputStream;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.internal.oxm.ByteArraySource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.oxm.annotations.*;
import org.junit.*;
class Container {
@XmlVariableNode("key")
List<Entry> entries = new ArrayList<Entry>();
}
class Entry {
@XmlTransient
public String key;
@XmlValue
@XmlNullPolicy(nullRepresentationForXml=XmlMarshalNullRepresentation.XSI_NIL, xsiNilRepresentsNull=false)
public String value;
}
public class D {
/** THIS TEST FAILS!!! */
@Test
public void unmarshallNull() throws Exception {
Assert.assertEquals(null, unmarshall("xml", "<root><color xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/" xsi:nil=/"true/"/></root>"));
Assert.assertEquals(null, unmarshall("json", "{/"color/":null}"));
}
/* All other tests are passing. */
@Test
public void unmarshallEmpty() throws Exception {
Assert.assertEquals("", unmarshall("xml", "<root><color></color></root>"));
Assert.assertEquals("", unmarshall("json", "{/"color/":/"/"}"));
}
@Test
public void unmarshallValue() throws Exception {
Assert.assertEquals("red", unmarshall("xml", "<root><color>red</color></root>"));
Assert.assertEquals("red", unmarshall("json", "{/"color/":/"red/"}"));
}
@Test
public void marshallNull() throws Exception {
Assert.assertEquals("<color xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/" xsi:nil=/"true/"/>", marshall("xml", null));
Assert.assertEquals("{/"color/":null}", marshall("json", null));
}
@Test
public void marshallEmpty() throws Exception {
Assert.assertEquals("<color></color>", marshall("xml", ""));
Assert.assertEquals("{/"color/":/"/"}", marshall("json", ""));
}
@Test
public void marshallValue() throws Exception {
Assert.assertEquals("<color>red</color>", marshall("xml", "red"));
Assert.assertEquals("{/"color/":/"red/"}", marshall("json", "red"));
}
private static String marshall(String format, String value) throws JAXBException {
// prepare
JAXBContext jc = JAXBContext.newInstance(Container.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(JAXBContextProperties.MEDIA_TYPE, "application/"+format);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
// define example data
Container detail = new Container();
Entry entry = new Entry();
entry.key = "color";
entry.value = value;
detail.entries.add(entry);
// marshall
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
marshaller.marshal(detail, outputStream);
return outputStream.toString();
}
private static String unmarshall(String format, String raw) throws JAXBException {
// prepare
JAXBContext jc = JAXBContext.newInstance(Container.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setProperty(JAXBContextProperties.MEDIA_TYPE, "application/"+format);
unmarshaller.setProperty(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
// unmarshall
Container container = unmarshaller.unmarshal(new ByteArraySource(raw.getBytes()), Container.class).getValue();
return container.entries.get(0).value;
}
}
Funciona para XML pero falla para JSON:
Test failure: unmarshallNull
java.lang.AssertionError: expected:<null> but was:<>
También configuré MOXy como mi proveedor jaxb para el paquete relevante ( jaxb.properties
):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Estoy usando MOXy 2.22.1
y Java8 (pero el mismo comportamiento con 2.18
, 2.19
, 2.20
, 2.21
, 2.22
). Mi Maven pom.xml
:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>x</groupId>
<artifactId>x</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.22.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>