[英]How can I use @JsonTypeInfo and @JsonSubTypes to instantiate Classes with different configurations?
我想創建一個配置文件,允許我定義不同的數據生成器,每個數據生成器都需要不同的配置。 但是,它們都共享相同的方法generateRow
,因此這些類都可以實現一個接口。 我正在使用傑克遜版本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
數據生成器節點的節點在我的配置文件。 我如何正確設置我的具體類來定義生成數據所需的屬性?
在我的引導代碼中,我實例化整個配置對象,如下所示:
new ObjectMapper().readValue(inputStream, DataGeneratorConfig.class);
為簡潔起見,我省略了getter和setter,以及配置文件的其余部分,這與手頭的問題無關。 如果我可以提供任何其他詳細信息或代碼,請告訴我們。
我對你的類的底層實現以及它們生成的數據等有點不確定。
但是你是按照正確的方式排列的,我推動了我認為這個回購的實際例子,注意這是使用https://projectlombok.org/來生成POJO,因為我很懶。
https://github.com/Flaw101/jackson-type-info
Data
類中來處理它。 測試中的ObjectMapper啟用了此功能所需的功能。 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只是混凝土沖擊的標記界面。
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或空屬性,並且接口具有正確的實現。
注意,這使用來自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);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.