簡體   English   中英

如何使用@JsonTypeInfo和@JsonSubTypes來實例化具有不同配置的類?

[英]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-in​​fo

  • 它將忽略“數據”節點。 這主要是因為我很懶,實體可以包裝在Data類中來處理它。 測試中的ObjectMapper啟用了此功能所需的功能。
  • 它將讀/寫配置類的數據。 與您指定的示例內聯。
  • 自動取消數據化是沒有快速的勝利。 你可能只是將它寫入一個地圖 - >對象,但這是非常混亂的,並使用像lombok / IDE類geneartion這樣的工具使這些實體應該是工作的秒。

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或空屬性,並且接口具有正確的實現。

注意,這使用來自AssertJassertThat

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM