首页 > 解决方案 > 具有可变 Json 响应对象和 Json 属性的杰克逊泛型

问题描述

根据 VizGhar 的回答“ Jackson Generics with variable JsonProperty ”,我正在尝试使用 WebClient 来使用 API 响应,其中包含 json 响应中的通用对象:

{
"meta": { 
    "RID": "abc9f-defgh-hj78k-lkm9n",
    "QID": "abc9f-defgh-hj78k-lkm9n" },
"data": { 
        "Inquiry": {
            "multiCurrency": [{"TaxStat": "Y", "TaxAmt": 0}],
            "Type": "Tax",
            "TaxFreq": { 
                "weekDay": 0,
                "startDay": 0 
            },
            "TaxRegion": "Tx" 
        } 
    }
}

“查询”的类型是通用的,即“数据”是通用响应对象的包装,在这种情况下是“查询”,但它可能会改变。

查询.java:

public class Inquiry {
    @JsonProperty("multiCurrency")
    private List<MultiCurrencyInq> multiCurrency;

    @JsonProperty("Type")
    private String Type;

    @JsonProperty("TaxFreq")
    private TaxFreq taxFreq;

    @JsonProperty("TaxRegion")
    private String TaxRegion;

    // Getters Setters Constructors
}

MultiCurrencyInq.java:

public class MultiCurrencyInq {

    @JsonProperty("TaxStat")
    private String TaxStat;

    @JsonProperty("TaxAmt")
    private int TaxAmt;

    // Getters Setters Constructors
}

TaxFreq.java:

public class TaxFreq {

    @JsonProperty("weekDay")
    private int weekDay;

    @JsonProperty("startDay")
    private int startDay;

    // Getters Setters Constructors
}

我的 Response.java 看起来像这样:

public class Response<T>{
    private Meta meta;
    private Data<T> data;
    // Getters Setters Constructors
}

元.java:

public class Meta{
    private String RID;
    private String QID;
    // Getters Setters Constructors
}

数据.java:

public class Data<T> {
    // property name, that will be changed
    @JsonProperty(DataNamingStrategy.DATA_FIELD)
    private T data;
    // Getters Setters Constructors
}

我的控制器:

@RestController
public class InquiryController {

    @Autowired private WebClient webClient;

    @GetMapping("/inquiry") public Response<Inquiry> getInquiryApiResponse() {
        ResponseEntity<String> response = webClient.get()
                .uri("http://my.org.com/clientId/inquiry")
                .retrieve()
                .toEntity(String.class)
                .block();

        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(new DataNamingStrategy("Inquiry")); 
        JavaType type = mapper.getTypeFactory()
                .constructParametricType(Response.class, Inquiry.class);

        Response<Inquiry> res = mapper.readValue(response.getBody(), type);
        return res;
    }
}

数据命名策略.java:

public class DataNamingStrategy extends PropertyNamingStrategy{

    // used by other classes (this will be default field name that should be changed)
    public static final String DATA_FIELD = "variable:data";
    private String fieldName;

    public DataNamingStrategy(String fieldName) {
        this.fieldName = fieldName;
    }

    // use this to change field name (format "variable":"value") not needed in my case
    @Override
    public String nameForField(MapperConfig<?> config, AnnotatedField field,
            String defaultName) {
        return (defaultName.equals(DATA_FIELD))?
            fieldName :
            super.nameForField(config, field, defaultName);
    }

    // use this to change setter method field name (JSON -> Object with format "variable":{})
    @Override
    public String nameForSetterMethod(MapperConfig<?> config,
            AnnotatedMethod method, String defaultName) {
        return (defaultName.equals(DATA_FIELD))?
            fieldName :
            super.nameForGetterMethod(config, method, defaultName);
    }

    // use this to change getter method field name (Object -> JSON with format "variable":{})
    // should be same as nameForSetterMethod
    @Override
    public String nameForGetterMethod(MapperConfig<?> config,
            AnnotatedMethod method, String defaultName) {
        return nameForSetterMethod(config, method, defaultName);
    }
}

这对我不起作用。在 Data.java 中未将@JsonProperty(DataNamingStrategy.DATA_FIELD)的泛型类型设置为“查询”的原因可能是什么

标签: javajsonspring-bootjackson

解决方案


在 Data.java 中未将 @JsonProperty(DataNamingStrategy.DATA_FIELD) 的泛型类型设置为“查询”的原因可能是什么

原因是默认情况下JsonProperty带注释的属性名称不能由DataNamingStrategy. Jackson 具有默认禁用的此功能。

ALLOW_EXPLICIT_PROPERTY_RENAMING 启用后将允许显式命名的属性(即,使用 JsonProperty("explicitName") 注释的字段或方法)由 PropertyNamingStrategy 重命名(如果已配置)的功能。默认情况下禁用该功能。

自:2.7

您需要做的就是启用此功能 -

ObjectMapper mapper = new ObjectMapper();
mapper.enable(MapperFeature.ALLOW_EXPLICIT_PROPERTY_RENAMING);

这是相关的杰克逊笔记历史(参考这里

Prior versions allowed explicit property renaming by default
v2.4 - Jackson stopped allowing property renaming. (#428)
v2.7 - Introduced ALLOW_EXPLICIT_PROPERTY_RENAMING feature to allow / disallow Explicit Property renaming (#918)

   

推荐阅读