簡體   English   中英

Jackson:將缺少的字段反序列化為 Kotlin/Java 列表

[英]Jackson: deserialize missing field to Kotlin/Java List

我有自己問題的答案,因此我發布了答案和解決方案,這是 Jeff Atwood 明確鼓勵的。 My question was originally for Kotlin, but while trying to find a solution, I also tried Java, so I provide the question and solution in both Java and Kotlin.)

Kotlin 中的問題

鑒於此可反序列化Product class:

data class Product(val name: String, val prices: List<Int>)

而這個缺少prices字段的 json 字符串:

{"name": "Computer"}

如何使用 Jackson 將 json 字符串反序列化為Product object?

我在 Kotlin 中嘗試過的

我試過這個:

data class Product(val name: String, val prices: List<Int>)

// Missing "prices" field
val json = """{"name": "Computer"}"""

// "prices" field included works fine
// val json = """{"name": "Computer", "prices": [1,2,3]}"""

val mapper = ObjectMapper().registerKotlinModule()
val product = mapper.readValue<Product>(json)
println(product)

但這會導致此異常:

com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException: Instantiation of 
[simple type, class MainKt$main$Product] value failed for JSON property prices due to 
missing (therefore NULL) value for creator parameter prices which is a non-nullable type
 at [Source: (String)"{"name": "Computer"}"; line: 1, column: 20] 
(through reference chain: MainKt$main$Product["prices"])

使用 Java 時

對於 Java, Product class 將是:

class Product {
    private String name;
    private List<Integer> prices;

    public Product(String name, List<Integer> prices) {
        this.name = name;
        this.prices = prices;
    }

    @Override
    public String toString() {
        return "Product{name='" + name + "\", prices=" + prices + '}';
    }
}

使用此 Jackson 代碼:

String json = "{\"name\": \"Computer\"}";
// String json = "{\"name\": \"Computer\", \"prices\": [1,2,3]}";

ObjectMapper mapper = new ObjectMapper();
// ParameterNamesModule is needed for non-arg constructor when not using Jackson annotations
mapper.registerModule(new ParameterNamesModule());
Product product = mapper.readValue(json, Product.class);

// Shows "prices=null", while "prices=[]" is required
System.out.println(product);

但這將prices設置為null而不是空列表。

Kotlin 中的解決方案

此解決方案適用於 Jackson 2.11 及更高版本。 它使用jackson-module-kotlin Maven 工件。

val kotlinModule = KotlinModule.Builder()
    .configure(KotlinFeature.NullToEmptyCollection, true)
    .build()
val mapper = ObjectMapper().registerModule(kotlinModule)

val product = mapper.readValue(json, Product::class.java)
println(product)

所以該解決方案使用KotlinFeature.NullToEmptyCollection ,它具有以下文檔:

默認值:假。 是否將集合屬性的 null 值反序列化為空 collections。

還有一個 map 版本: KotlinFeature.NullToEmptyMap

對於 2.9 和 2.10 版本,您可以使用KotlinModule構造函數的nullToEmptyCollection默認參數。

Java中使用注解的解決方案

注釋Product class:

class Product {
    private String name;
    private List<Integer> prices;

    public Product(@JsonProperty("name") String name, 
                   @JsonProperty("prices") 
                   @JsonSetter(nulls = Nulls.AS_EMPTY) List<Integer> prices
    ) {
        this.name = name;
        this.prices = prices;
    }

    @Override
    public String toString() {
        return "Product{name='" + name + "\', prices=" + prices + '}';
    }
}

Jackson 代碼:

String json = "{\"name\": \"Computer\"}";
ObjectMapper mapper = new ObjectMapper();
Product product = mapper.readValue(json, Product.class);
System.out.println(product); // Product{name='Computer', prices=[]}

該解決方案的關鍵部分是@JsonSetter(nulls = Nulls.AS_EMPTY) ,它將缺失的或 null json 字段設置為 ZD52387880E1EA22817A72D3759Z23 中的空列表。

可以通過使用jackson-module-parameter-names Maven 工件來減少詳細注釋的數量,例如@JsonProperty("prices") 然后只需要@JsonSetter(nulls = Nulls.AS_EMPTY)

Java中沒有注釋的解決方案

此解決方案需要jackson-module-parameter-names Maven 工件。 使用此模塊/工件時,不要忘記添加-parameters編譯器參數。

Product class Jackson 無注釋:

class Product {
    private String name;
    private List<Integer> prices;

    public Product(String name, List<Integer> prices) {
        this.name = name;
        this.prices = prices;
    }

    @Override
    public String toString() {
        return "Product{name='" + name + "\", prices=" + prices + '}';
    }
}

Jackson 代碼:

String json = "{\"name\": \"Computer\"}";

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParameterNamesModule());
mapper.setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));

Product product = mapper.readValue(json, Product.class);
System.out.println(product);

需要ParameterNamesModule model 以允許 Jackson 按名稱反映Product構造函數參數,因此不再需要@JsonProperty("prices") JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)用於將缺失或 null json 字段轉換為列表。

您的產品 class 需要實現可序列化 class。 它可以制作一致性數據。

class Product implements Serializable {
    ..............
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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