gpt4 book ai didi

java - 如何使用@JsonTypeInfo 和@JsonSubTypes 来实例化具有不同配置的类?

转载 作者:搜寻专家 更新时间:2023-11-01 02:57:46 25 4
gpt4 key购买 nike

我想创建一个配置文件,允许我定义不同的数据生成器,每个生成器都需要不同的配置。但是,它们都共享相同的方法 generateRow,因此这些类都可以实现一个接口(interface)。我使用的是 Jackson 2.9.4 版。

为了说明,这里有两个示例配置文件:

{
"data": {
"type": "standard",
"config": {
"rows": 1000,
"columns": 10
}
}
}

{
"data": {
"type": "totalSize",
"config": {
"sizeInBytes": 1073741824,
"cellDensityInBytes": 12,
"columns": 5
}
}
}

第一个数据生成器简单地创建一个具有给定行数和列数的文件,第二个生成器创建一个预定义大小的文件,确定满足配置变量所需的行数(即列数和细胞密度)。

所以,我创建了一个界面:

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = IGenerateRows.PROPERTY, defaultImpl = StandardRowGenerator.class)
@JsonSubTypes(value = { @Type(StandardRowGenerator.class) })
public interface IGenerateRows {

public static final String PROPERTY = "type";

public String[] generateRow();
}

我至少有一个具体的实现:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;

@JsonTypeName(value = StandardRowGenerator.TYPE)
public class StandardRowGenerator {

public static final String TYPE = "standard";

private static final String ROWS = "rows";
private static final String COLUMNS = "columns";

@JsonProperty(value = ROWS, required = true)
private int rows;

@JsonProperty(value = COLUMNS, required = true)
private int columns;
}

我想不通的是,如何在我的配置文件中处理数据生成器节点的 config 节点。我将如何正确设置我的具体类来定义它们生成数据所需的属性?

在我的 Bootstrap 代码中,我将整个配置对象实例化如下:

new ObjectMapper().readValue(inputStream, DataGeneratorConfig.class);

为简洁起见,我省略了 getter 和 setter,以及与当前问题无关的配置文件的其余部分。如果我可以提供任何其他详细信息或代码,请告诉我。

最佳答案

我有点不确定你的类的底层实现以及它们生成的数据等。

但是您的路线是正确的,我已经将我认为是您正在寻找的工作示例推送到此 repo,注意这是使用 https://projectlombok.org/生成 POJO 因为我很懒。

https://github.com/Flaw101/jackson-type-info

  • 它将忽略“数据”节点。这主要是因为我又懒了,实体可以包装在 Data 类中来处理它。测试中的 ObjectMapper 启用了为此所需的功能。
  • 它将读取/写入配置类的数据。与您指定的示例内联。
  • 自动反序列化数据没有立竿见影的效果。您也许可以将其写入 map -> 对象,但这非常困惑,并且使用 lombok/IDE 类生成等工具制作这些实体应该是几秒钟的工作。

IGenerateRow 看起来像,

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = RowGenerator.PROPERTY, defaultImpl = StandardRowGenerator.class)
@JsonSubTypes(value = { @Type(StandardRowGenerator.class), @Type(TotalSizeGeneartor.class) })
@JsonRootName(value = "data")
public abstract interface RowGenerator {

public static final String PROPERTY = "type";

Config getConfig();
}

Config只是具体实现的标记接口(interface)。

public interface Config {



}

SimpleTypeGenerator 现在变成了,

@JsonTypeName(value = StandardRowGenerator.TYPE)
@Data

public class StandardRowGenerator implements RowGenerator {

public static final String TYPE = "standard";

private StandardConfig config;

@Data
public static class StandardConfig implements Config {
private int rows;
private int columns;
}
}

TotalSize 类似,

@JsonTypeName(value = TotalSizeGeneartor.TYPE)
@Data
public class TotalSizeGeneartor implements RowGenerator {

public static final String TYPE = "totalSize";

private TotalSizeConfig config;

@Data
public static class TotalSizeConfig implements Config {
private long sizeInBytes;
private int cellDensityInBytes;
private int columns;
}
}

这些可以通过更多/更好的通用类型信息得到改进,以便能够获得对配置的具体引用。

测试类读取资源文件夹中的两个配置,将它们写入对象并返回一个字符串,比较之前/之后,没有 null 或空属性,并且接口(interface)是正确的实现。

请注意,这使用了 AssertJ 中的 assertThat

public class JacksonTest {

private ObjectMapper mapper;
private String json;

@Before
public void setup() throws Exception {
mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
}

@Test
public void testDeserStandard() throws Exception {
json = StringUtils.deleteWhitespace(
new String(Files.readAllBytes(Paths.get("src/main/resources/standard.json")), StandardCharsets.UTF_8));

RowGenerator generator = mapper.readValue(json, RowGenerator.class);
assertThat(generator).hasNoNullFieldsOrProperties().isExactlyInstanceOf(StandardRowGenerator.class);
assertThat(generator.getConfig()).hasNoNullFieldsOrProperties().isExactlyInstanceOf(StandardConfig.class);
assertThat(json).isEqualTo(mapper.writeValueAsString(generator));
System.out.println(generator);
}

@Test
public void testDeserTotalsize() throws Exception {
json = StringUtils.deleteWhitespace(
new String(Files.readAllBytes(Paths.get("src/main/resources/totalsize.json")), StandardCharsets.UTF_8));

RowGenerator generator = mapper.readValue(json, RowGenerator.class);
assertThat(generator).hasNoNullFieldsOrProperties().isExactlyInstanceOf(TotalSizeGeneartor.class);
assertThat(generator.getConfig()).hasNoNullFieldsOrProperties().isExactlyInstanceOf(TotalSizeConfig.class);
assertThat(json).isEqualTo(mapper.writeValueAsString(generator));
System.out.println(generator);

}

}

关于java - 如何使用@JsonTypeInfo 和@JsonSubTypes 来实例化具有不同配置的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48931606/

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