gpt4 book ai didi

java - 如何根据父类中可用的信息进行反序列化

转载 作者:搜寻专家 更新时间:2023-10-31 20:00:15 27 4
gpt4 key购买 nike

我正在使用 Jackson 反序列化 Product 接口(interface)的多个不同实现。这些产品实现有不同的字段,但都有一个 InsuredAmount 字段。此 InsuredAmount 类有一个值字段和一个 IAType 字段。 IAType 是一个标记接口(interface),具有不同的枚举作为实现。

现在问题来了:IAType 接口(interface)的枚举实现对应于Product 接口(interface)的某个实现。我如何进行通用实现并告诉 Jackson 找到 IAType 的正确实现?我是否应该在 Product 上使用通用参数和标识产品实现的 IAType 接口(interface)?我应该在标识产品实现的类上使用 Productable 功能接口(interface)吗?我如何告诉 Jackson 使用该实现?

我希望下面的代码能说明问题,我选择在这里实现一个 Productable 接口(interface),但也欢迎有更好的结构来处理这个问题。

@JsonPropertyOrder({"type", "someInfo"})
public class InsuredAmount implements Productable, Serializable {

private static final long serialVersionUID = 1L;

private IAType type;

private String someInfo;

public InsuredAmount() {
}

public InsuredAmount(IAType typeA, String someInfo) {
this.type = typeA;
this.someInfo = someInfo;
}


/* This should be on the product level, but if I can solve this problem,
the next level will just be more of the same.
*/
@JsonIgnore
@Override
public Product getProduct() {
return Product.PROD_A;
}

// Getters, setters, equals, etc. omitted.
}

--

public interface Productable {

public Product getProduct();

}

--

public enum Product {

PROD_A, PROD_B;

}

--

@JsonDeserialize(using = IATypeDeserializer.class)
public interface IAType extends Productable {

}

--

public enum IATypeA implements IAType {

FOO, BAR;

@Override
public Product getProduct() {
return Product.PROD_A;
}

}

--

public class IATypeDeserializer extends StdDeserializer<IAType> {

private static final long serialVersionUID = 1L;

public IATypeDeserializer() {
this(null);
}

public IATypeDeserializer(Class<?> vc) {
super(vc);
}

@Override
public IAType deserialize(JsonParser parser, DeserializationContext context)
throws IOException, JsonProcessingException {
JsonNode node = parser.getCodec().readTree(parser);
/* How to find out that the class calling the deserialization is InsuredAmountA, which
has getProduct() method that returns PROD_A, and matches the IATypeA that also returns
PROD_A, so I know to deserialize IATypeA, instead of other implementations of the IAType
interface?
*/
return IATypeA.valueOf(node.asText());
}

}

--

public class InsuredAmountTest {

private final ObjectMapper mapper = new ObjectMapper();

@Test
public void test01() throws IOException {
InsuredAmount iaA = new InsuredAmount(IATypeA.FOO, "test it");
String json = mapper.writeValueAsString(iaA);
assertThat(json, is("{\"type\":\"FOO\",\"someInfo\":\"test it\"}"));
InsuredAmount iaA2 = mapper.readValue(json, InsuredAmount.class);
IAType type = iaA2.getType();
assertThat(type, is(IATypeA.FOO));
assertThat(type.getProduct(), is(Product.PROD_A));
assertThat(iaA, is(iaA2));
}

@Test
public void test02() throws IOException {
InsuredAmount iaA = new InsuredAmount(IATypeA.BAR, "test it");
String json = mapper.writeValueAsString(iaA);
assertThat(json, is("{\"type\":\"BAR\",\"someInfo\":\"test it\"}"));
InsuredAmount iaA2 = mapper.readValue(json, InsuredAmount.class);
assertThat(iaA, is(iaA2));
}

}

最佳答案

Jackson 以最小的麻烦处理枚举的序列化,因此您需要做的就是使用 @JsonTypeInfo 注释 IAType 字段:

@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)
private IAType type;

然后是测试:

public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new InsuredAmount(IATypeA.FOO, "info"));
System.out.println(json);
InsuredAmount ia = mapper.readValue(json, InsuredAmount.class);
System.out.println("Type is: " + ia.getType());
}

输出结果:

{"type":[".IATypeA","FOO"],"someInfo":"info"}
Type is: FOO

要获得更紧凑的表示,您将不得不使用自定义序列化。假设您的枚举命名空间中没有重叠,您可以将类型字段序列化为枚举名称。

反序列化器需要知道哪些类型可用于构造,要么通过类路径发现,要么像下面的示例那样,简单地对引用进行硬编码:

public class IATest {

public static class IATypeSerializer extends JsonSerializer<IAType> {
@Override
public void serialize(IAType value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(((Enum) value).name());
}
}

public static class IATypeDeserializer extends JsonDeserializer<IAType> {
@Override
public IAType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = p.readValueAs(String.class);
try {
return IATypeA.valueOf(value);
} catch (IllegalArgumentException e) {
// fall through
}
try {
return IATypeB.valueOf(value);
} catch (IllegalArgumentException e) {
// fall through
}
throw new JsonMappingException(p, "Unknown type '" + value + "'");
}
}

public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();

// Register a module to handle serialization of IAType implementations
SimpleModule module = new SimpleModule();
module.addSerializer(IAType.class, new IATypeSerializer());
module.addDeserializer(IAType.class, new IATypeDeserializer());
mapper.registerModule(module);

// Test
String json = mapper.writeValueAsString(new InsuredAmount(IATypeA.FOO, "info"));
System.out.println(json);
InsuredAmount ia = mapper.readValue(json, InsuredAmount.class);
System.out.println("Type is: " + ia.getType());
}

}

哪些输出:

{"type":"FOO","someInfo":"info"}
Type is: FOO

关于java - 如何根据父类中可用的信息进行反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42022981/

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