我使用一个父接口Vehicle概念,其中包含两个类Car和Truck。
在你的情况下,这意味着Model1和Model2应该实现一个公共接口。
我的测试类:
import com.fasterxml.jackson.databind.ObjectMapper;
public class Tester {
static ObjectMapper mapper=new ObjectMapper();
public static void main(String[] args) throws IOException {
Car car = new Car();
car.setModel("sedan");
String jsonCar=mapper.writeValueAsString(car);
System.out.println(jsonCar);
Vehicle c=mapper.readValue(jsonCar, Vehicle.class);
System.out.println("Vehicle of type: "+c.getClass().getName());
Truck truck=new Truck();
truck.setPower(100);
String jsonTruck=mapper.writeValueAsString(truck);
System.out.println(jsonTruck);
Vehicle t=mapper.readValue(jsonTruck, Vehicle.class);
System.out.println("Vehicle of type: "+t.getClass().getName());
}
}
你需要在某个地方存储一个类型字段值和相应类之间的映射关系。具体实现取决于你想要存放的位置。
1)父类型保存子类型列表:
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonSubTypes({
@JsonSubTypes.Type(value = Car.class, name = "car"),
@JsonSubTypes.Type(value = Truck.class, name = "truck") }
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
public interface Vehicle {
}
Car和Truck的模型是简单的POJO,没有任何注释:
public class Car implements Vehicle {
private String model;
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
2) 单独的解析器保存映射关系:
Vehicle 包含额外的注释 @JsonTypeIdResolver
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonTypeIdResolver(JsonResolver.class)
public interface Vehicle {
}
JsonResolver 类保存类型字段值和类之间的映射关系。
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase;
public class JsonResolver extends TypeIdResolverBase {
private static Map<String,Class<?>> ID_TO_TYPE=new HashMap<>();
static {
ID_TO_TYPE.put("car",Car.class);
ID_TO_TYPE.put("truck",Truck.class);
}
public JsonResolver() {
super();
}
@Override
public Id getMechanism() {
return null;
}
@Override
public String idFromValue(Object value) {
return value.getClass().getSimpleName();
}
@Override
public String idFromValueAndType(Object value, Class<?> arg1) {
return idFromValue(value);
}
@Override
public JavaType typeFromId(DatabindContext context, String id) {
return context.getTypeFactory().constructType(ID_TO_TYPE.get(id));
}
}
3)json中包含完整的类名:
如果您接受序列化的json包含完整的Java类名,则无需解析器,但需指定use = JsonTypeInfo.Id.CLASS
:
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
@JsonTypeInfo(
use = JsonTypeInfo.Id.CLASS,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
public interface Vehicle {
}
解决方案3是最容易实现的,但我个人不喜欢在我的数据中使用完整的Java类名。如果您开始重构Java包,这可能会带来潜在风险。
Model1
和Model2
没有共同的父类(除了Object
之外)也没有共同的接口,因此您的mapJsonToObject
函数除了返回Object
类型之外,无法获得适当的返回类型。 您想对返回的对象做什么? 由于您不知道它是什么类型,因此无法对某些超类型执行常规逻辑。 - roookeeeModel1
和Model2
序列化为其他类型,对吗?正如我所解释的那样-它们没有共同的超类型,因此只能使用类似于访问者模式的东西来实现。如果您有兴趣,我可以将一个示例添加为答案。 - roookeeeMap
。据我所知,任何其他做这种事情的库/框架都需要你提供一个正确的类型,否则序列化/反序列化将失败。 - x80486