sirve - ¿Cómo puedo deserializar polimórficos Json String usando Java y la Biblioteca Jackson?
polimorfismo en java netbeans (2)
¿Has mirado la biblioteca Gson de Google? Creo que hace lo que estás buscando.
Tengo algunas clases A, B, C, todas ellas heredan de la clase BaseClass.
Tengo un String json que contiene la representación json de A, B, C o BaseClass.
Quiero tener alguna manera de deserializar esta Cadena a la Clase de Base (deserialización polimórfica). Algo como esto
BaseClass base = ObjectMapper.readValue(jsonString, BaseClass.class);
jsonString
podría ser una representación Json String de cualquiera de A, B, C o BaseClass.
No está claro qué problema está teniendo el póster original. Supongo que es una de dos cosas:
Problemas de deserialización con elementos JSON no enlazados, porque el JSON contiene elementos para los cuales no hay nada en el que enlazarse; o
Desea implementar la deserialización polimórfica.
Aquí hay una solución al primer problema.
import static org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES;
import org.codehaus.jackson.map.ObjectMapper;
public class Foo
{
public static void main(String[] args) throws Exception
{
BaseClass base = new BaseClass();
A a = new A();
B b = new B();
C c = new C();
ObjectMapper mapper = new ObjectMapper();
String baseJson = mapper.writeValueAsString(base);
System.out.println(baseJson); // {"baseName":"base name"}
String aJson = mapper.writeValueAsString(a);
System.out.println(aJson); // {"baseName":"base name","aName":"a name"}
String bJson = mapper.writeValueAsString(b);
System.out.println(bJson); // {"baseName":"base name","bName":"b name"}
String cJson = mapper.writeValueAsString(c);
System.out.println(cJson); // {"baseName":"base name","cName":"c name"}
BaseClass baseCopy = mapper.readValue(baseJson, BaseClass.class);
System.out.println(baseCopy); // baseName: base name
// BaseClass aCopy = mapper.readValue(aJson, BaseClass.class);
// throws UnrecognizedPropertyException:
// Unrecognized field "aName", not marked as ignorable
// because the JSON contains elements for which no Java field
// to bind to was provided.
// Need to let Jackson know that not all JSON elements must be bound.
// To resolve this, the class can be annotated with
// @JsonIgnoreProperties(ignoreUnknown=true) or the ObjectMapper can be
// directly configured to not FAIL_ON_UNKNOWN_PROPERTIES
mapper = new ObjectMapper();
mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
BaseClass aCopy = mapper.readValue(aJson, BaseClass.class);
System.out.println(aCopy); // baseName: base name
BaseClass bCopy = mapper.readValue(bJson, BaseClass.class);
System.out.println(bCopy); // baseName: base name
BaseClass cCopy = mapper.readValue(cJson, BaseClass.class);
System.out.println(cCopy); // baseName: base name
}
}
class BaseClass
{
public String baseName = "base name";
@Override public String toString() {return "baseName: " + baseName;}
}
class A extends BaseClass
{
public String aName = "a name";
@Override public String toString() {return super.toString() + ", aName: " + aName;}
}
class B extends BaseClass
{
public String bName = "b name";
@Override public String toString() {return super.toString() + ", bName: " + bName;}
}
class C extends BaseClass
{
public String cName = "c name";
@Override public String toString() {return super.toString() + ", cName: " + cName;}
}
Aquí hay una solución al segundo problema.
import org.codehaus.jackson.annotate.JsonSubTypes;
import org.codehaus.jackson.annotate.JsonSubTypes.Type;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.map.ObjectMapper;
public class Foo
{
public static void main(String[] args) throws Exception
{
BaseClass base = new BaseClass();
A a = new A();
B b = new B();
C c = new C();
ObjectMapper mapper = new ObjectMapper();
String baseJson = mapper.writeValueAsString(base);
System.out.println(baseJson); // {"type":"BaseClass","baseName":"base name"}
String aJson = mapper.writeValueAsString(a);
System.out.println(aJson); // {"type":"a","baseName":"base name","aName":"a name"}
String bJson = mapper.writeValueAsString(b);
System.out.println(bJson); // {"type":"b","baseName":"base name","bName":"b name"}
String cJson = mapper.writeValueAsString(c);
System.out.println(cJson); // {"type":"c","baseName":"base name","cName":"c name"}
BaseClass baseCopy = mapper.readValue(baseJson, BaseClass.class);
System.out.println(baseCopy); // baseName: base name
BaseClass aCopy = mapper.readValue(aJson, BaseClass.class);
System.out.println(aCopy); // baseName: base name, aName: a name
BaseClass bCopy = mapper.readValue(bJson, BaseClass.class);
System.out.println(bCopy); // baseName: base name, bName: b name
BaseClass cCopy = mapper.readValue(cJson, BaseClass.class);
System.out.println(cCopy); // baseName: base name, cName: c name
}
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@Type(value = A.class, name = "a"),
@Type(value = B.class, name = "b"),
@Type(value = C.class, name = "c") })
class BaseClass
{
public String baseName = "base name";
@Override public String toString() {return "baseName: " + baseName;}
}
class A extends BaseClass
{
public String aName = "a name";
@Override public String toString() {return super.toString() + ", aName: " + aName;}
}
class B extends BaseClass
{
public String bName = "b name";
@Override public String toString() {return super.toString() + ", bName: " + bName;}
}
class C extends BaseClass
{
public String cName = "c name";
@Override public String toString() {return super.toString() + ", cName: " + cName;}
}
Si, en cambio, el objetivo es deserializar a un tipo de subclase sin un elemento JSON específicamente dedicado a indicar cuál es el tipo de subclase, entonces también es posible, siempre que se pueda usar algo en el JSON para decidir cuál debe ser el tipo de subclase . Publiqué un ejemplo de este enfoque en http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html .