gpt4 book ai didi

java - 动态选择从 json 创建对象的类

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:30:38 24 4
gpt4 key购买 nike

我有一个有趣的问题,我无法想出一个干净的解决方案。我的应用程序读取 json 对象的集合,它需要根据 json 本身中的字段反序列化为这种或那种类类型。我无法控制 json 结构或它如何到达我的应用程序。

我已经为可能进入应用程序的每种类型的对象创建了模型,并且我已经达到了我试图构建一个拉出“类型”字段然后使用 ObjectMapper 反序列化的服务的地步将 json 转换为适当的模型。

Json 示例:

{
"message_type" : "model1"
"other data" : "other value"
...
}

模型:

public class Model1 {
...
}

public class Model2 {
...
}

服务?

public class DynamicMappingService {

public ???? mapJsonToObject(String json) {
String type = pullTypeFromJson();

???
}

private String pullTypeFromJson() {...}
}

我不想要一个巨大的 switch 语句,它说“如果类型值是这个,那么反序列化到那个”,但我正在努力想出一些干净的东西来做到这一点。我想也许是一个通用模型类,其中通用参数是模型类型,唯一的字段是该模型类型的实例,但这似乎也不正确,我不确定这能给我带来什么。我也可以有某种空的抽象类,所有模型都可以扩展它,但这看起来也很糟糕。我该如何处理?举个例子加分。

最佳答案

我使用父接口(interface) Vehicle 的概念,它有两个类 CarTruck。在您的情况下,这意味着 Model1Model2 应该实现一个通用接口(interface)。

我的测试类:

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

CarTruck 的模型是简单的 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 包,这可能是一个潜在的风险。

关于java - 动态选择从 json 创建对象的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57102092/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com