使用继承、List 和子类解组 json 的问题

问题描述 投票:0回答:1

我有一个基类:

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME, property = "fieldType", include=JsonTypeInfo.As.EXISTING_PROPERTY, visible=true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = JobCurrencyField.class, name = "CURRENCY")
})
public abstract class BaseJobField {
    private String name;
    private Object value;
    private String fieldType;

    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();
        List<BaseJobField> jobFields = new ArrayList<>();
        jobFields.add(JobCurrencyField.create("currencyUS", "USD", 10.4));
        try {
            String fields = objectMapper.writeValueAsString(jobFields);
            List<BaseJobField> ret = objectMapper.readValue(fields, new TypeReference<List<BaseJobField>>(){});
            JobCurrencyField jobCurrencyField = (JobCurrencyField) ret.get(0);
            JobCurrencyField.Currency currency = (JobCurrencyField.Currency)jobCurrencyField.getValue();
        } catch (Exception x) {
            System.out.println(x.getMessage());
        }
    }
}

还有一个子类:

@Data
@NoArgsConstructor
@JsonTypeName("CURRENCY")
public class JobCurrencyField extends BaseJobField {
    @Data
    @NoArgsConstructor
    public static class Currency {
        private String currencyName;
        private double amount;
    }

    public static JobCurrencyField create(String name, String currencyName, Double amount) {
        Currency currency = new Currency();
        currency.setCurrencyName(currencyName);
        currency.setAmount(amount);
        JobCurrencyField jobCurrencyField = new JobCurrencyField();
        jobCurrencyField.setName(name);
        jobCurrencyField.setValue(currency);
        jobCurrencyField.setFieldType("CURRENCY");
        return jobCurrencyField;
    }
}

对象的解组,

objectMapper.readValue()
不会将内部类解组为JobCurrencyField.CURRENCY,而是解组为LinkedHashMap,因此:
JobCurrencyField.Currency currency = (JobCurrencyField.Currency)jobCurrencyField.getValue();

抛出异常:
java.util.LinkedHashMap cannot be cast to JobCurrencyField$Currency

如何告诉 objectMapper 将值解组到货币字段而不是 LinkedHashMap?

java json inheritance unmarshalling subtype
1个回答
0
投票

实现您想要的效果的一种方法是将

BaseJobField
类参数化为
BaseJobField<T>
,将
Currency
类移动到其自己的文件中,然后使
JobCurrencyField
类扩展
BaseJobField<Currency>
。课程最终如下所示:

BaseJobField.java:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME, property = "fieldType", include=JsonTypeInfo.As.EXISTING_PROPERTY, visible=true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = JobCurrencyField.class, name = "CURRENCY")
})
public abstract class BaseJobField<T> {
    private String name;
    private T value;
    private String fieldType;
}

Currency.java:

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class Currency {
    private String currencyName;
    private double amount;
}

JobCurrencyField.java:

import com.fasterxml.jackson.annotation.JsonTypeName;

import lombok.NoArgsConstructor;

@NoArgsConstructor
@JsonTypeName("CURRENCY")
public class JobCurrencyField extends BaseJobField<Currency> {

    public static JobCurrencyField create(String name, String currencyName, Double amount) {
        Currency currency = new Currency();
        currency.setCurrencyName(currencyName);
        currency.setAmount(amount);
        JobCurrencyField jobCurrencyField = new JobCurrencyField();
        jobCurrencyField.setName(name);
        jobCurrencyField.setValue(currency);
        jobCurrencyField.setFieldType("CURRENCY");
        return jobCurrencyField;
    }
}

测试验证反序列化:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.List;
import java.util.ArrayList;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class JacksonTest {

    @Test
    public void testDeserialize() throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        List<BaseJobField<?>> jobFields = new ArrayList<>();
        jobFields.add(JobCurrencyField.create("currencyUS", "USD", 10.4));
        String fields = objectMapper.writeValueAsString(jobFields);

        List<BaseJobField<?>> ret = objectMapper.readValue(fields, new TypeReference<List<BaseJobField<?>>>(){});
        JobCurrencyField jobCurrencyField = (JobCurrencyField) ret.get(0);
        Currency currency = (Currency)jobCurrencyField.getValue();

        Assertions.assertTrue(currency instanceof Currency);
        Assertions.assertEquals("USD", currency.getCurrencyName());
        Assertions.assertEquals(10.4d, currency.getAmount());
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.