不改变 POJO 的不区分大小写的 JSON 到 POJO 的映射

Posted

技术标签:

【中文标题】不改变 POJO 的不区分大小写的 JSON 到 POJO 的映射【英文标题】:Case insensitive JSON to POJO mapping without changing the POJO 【发布时间】:2014-11-21 10:09:23 【问题描述】:

有谁知道 com.fasterxml.jackson.databind.ObjectMapper 是如何将 JSON 属性映射到 POJO 属性不区分大小写的?

JSON 字符串:

["FIRSTNAME":"John","LASTNAME":"Doe","DATEOFBIRTH":"1980-07-16T18:25:00.000Z"]

POJO级:

public class Person 

    private String firstName;
    private String lastName;
    private Date dateOfBirth;

    public String getFirstName() 
        return firstName;
    
    public void setFirstName(String firstName) 
        this.firstName = firstName;
    
    public String getLastName() 
        return lastName;
    
    public void setLastName(String lastName) 
        this.lastName = lastName;
    
    public Date getDateOfBirth() 
        return dateOfBirth;
    
    public void setDateOfBirth(Date dateOfBirth) 
        this.dateOfBirth = dateOfBirth;
    

测试类:

@Test
public final void testDeserializingPersonJsonToPersonClass()
        throws JsonParseException, JsonMappingException, IOException 
    final String jsonAsString = "[\"FIRSTNAME\":\"John\",\"LASTNAME\":\"Doe\",\"DATEOFBIRTH\":\"1980-07-16T18:25:00.000Z\"]";
    final ObjectMapper mapper = new ObjectMapper();

    final Person person = mapper.readValue(jsonAsString, Person.class);

    assertNotNull(person);
    assertThat(person.getFirstName(), equalTo("John"));

这会导致以下错误: com.fasterxml.jackson.databind.JsonMappingException:无法反序列化...的实例

既不能更改 JSON-String 也不能更改 POJO-Class。

【问题讨论】:

既不能改变JSON-String也不能改变POJO-Class,那就不可能了。 【参考方案1】:

此行为是在 Jackson 2.5.0 中引入的。您可以使用 MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES 将映射器配置为不区分大小写。

例如:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);

【讨论】:

【参考方案2】:

如@Nicolas Riousset 所述,您可以通过配置映射器来解决此问题。

此外,从 Jackson 2.9 版本开始,您可以在字段或类上使用注解 @JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) 执行相同操作,这是一种更灵活的选择。

@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
private String firstName;

【讨论】:

我在至少使用 jackson 2.9 的 Spring Boot 应用程序中进行了尝试,但似乎没有帮助。我的用例不同吗?我乐观地认为有解决方案,但我还没有找到任何东西......我想相信:) @user1445967,您如何使用此功能?您还有其他 Jackson 映射配置吗? 我说的是 Spring [Boot] MVC 中的“普通”@RequestMapping / @GetMapping / @PostMapping,其中 @RequestBody 注释放置在用于存储 JSON 属性的对象之前。出于这个原因,我们不会(故意)尝试配置 Jackson 的任何部分... 自 2020 年 5 月起,您不能在课程级别应用此映射器功能。此类功能仍未实现。目前预定 Jackson 2.12 版github.com/FasterXML/jackson-databind/issues/1886 不,该示例不起作用。注释仅适用于被注释元素对象中的属性,而不适用于被注释属性本身。没有单一属性不区分大小写!【参考方案3】:

我遇到了同样的问题,但找不到解决此问题的全局方法。但是,您可以为每个属性设置 2 个设置器来实现此目的:

@JsonSetter("FIRSTNAME")
public void setFirstNameCaps(String firstName) 
    this.firstName = firstName;


@JsonSetter("firstName")
public void setFirstName(String firstName) 
    this.firstName = firstName;

不优雅,但适用于大小写 json 字段。您也可以尝试here 提到的解决方案,但这可能会产生性能开销

【讨论】:

【参考方案4】:
package br.com.marcusvoltolim.util;


import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j;

@Log4j
public class JsonUtils 

    private static final ObjectMapper OBJECT_MAPPER;

    static 
        OBJECT_MAPPER = new ObjectMapper();
        OBJECT_MAPPER.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    

    public static <T> T fromJson(final String json, final Class<T> classe) 
        try 
            return OBJECT_MAPPER.readValue(json, classe);
         catch (Exception e) 
            log.error(e);
            try 
                return classe.newInstance();
             catch (InstantiationException | IllegalAccessException ex) 
                return null;
            
        
    


【讨论】:

【参考方案5】:

从 Jackson 2.12 版本开始,你终于可以在课堂上进行注解了:

@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public class Person 
    private String firstName;
    private String lastName;
    private Date dateOfBirth;
    // setters and getters ...

正如Github issue 中所述,仍然不支持单属性不区分大小写!

【讨论】:

【参考方案6】:

我遇到了同样的情况,不得不转换为地图,然后手动复制这些值。

import com.fasterxml.jackson.core.type.TypeReference;

Map<String, String> map = 
    mapper.readValue(jsonAsString, new TypeReference<Map<String, String>>());

【讨论】:

以上是关于不改变 POJO 的不区分大小写的 JSON 到 POJO 的映射的主要内容,如果未能解决你的问题,请参考以下文章

区分 json 中不存在字段的时间和将其值作为 null 发送的时间

使用 Hibernate Criteria 的不区分大小写的排序

接受所有数据类型的不区分大小写的 C++ 排序?

nvarchar 类型的不区分大小写的主键,其中 ß != ss

Entity Framework 7 中表和属性的不区分大小写的名称

在 C# 中具有字符串键类型的不区分大小写字典