You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot升级至1.3.0后JPA AttributeConverter空指针错误排查

Spring Boot 1.3.0.RELEASE升级后JPA AttributeConverter报错排查

背景

原Spring Boot 1.2.1.RELEASE版本中,使用JPA的AttributeConverter将Map<String, Object>转换为JSON字符串存入数据库可正常工作,升级到1.3.0.RELEASE后,添加包含metaDataAttribute字段的请求时触发内部服务器错误。

需求场景

需将以下JSON格式数据存入实体类对应字段:

metadata: {
          masked: true,
          maxLength: 200,
          formula: "a + b",
          parentCode: "strAttr_1",
          currency: "$",
        }

相关代码

实体类字段定义

@Column(name = "metadata_json",columnDefinition = "json")
@Convert(converter = HashMapConverter.class)
private Map<String,Object> metaDataAttribute;

HashMapConverter转换器代码

package in.nobroker.hood.crm.entity;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import javax.persistence.AttributeConverter;
import java.io.IOException;
import java.util.Map;

@Slf4j
public class HashMapConverter implements AttributeConverter<Map<String, Object>, String> {
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public String convertToDatabaseColumn(Map<String, Object> stringObjectMap) {
        String attributeInfoJson = null;
        try {
            attributeInfoJson = objectMapper.writeValueAsString(stringObjectMap);
        } catch (final JsonProcessingException e) {
            log.error("JSON writing error", e);
        }
        return attributeInfoJson;
    }

    @Override
    public Map<String, Object> convertToEntityAttribute(String s) {
        Map<String, Object> attributeInfo = null;
        try {
            attributeInfo = objectMapper.readValue(s, Map.class);
        } catch (final IOException e) {
            log.error("JSON reading error", e);
        }
        return attributeInfo;
    }
}

请求示例(Postman发送)

{
    "label": "dateAttr_5",
    "id": "f73434ba-bfaa-49f5-9a41-b86715a985f2",
    "filter": true,
    "inUse": true,
    "editable": true,
    "mandatory": true,
    "priority": 0,
    "textOptions": "a,b,c,d",
    "type": "DATETIME_FORM_DATA",
    "filterType": "ABSOLUTE",
    "metaDataAttribute": {
        "masked": true,
        "maxLength": 200,
        "formula": "a + b",
        "parentCode": "strAttr_1",
        "currency": "$"
    }
}

错误日志

argument "content" is null
failed to fetch attribute label mappings 
argument "content" is null
    at com.fasterxml.jackson.databind.ObjectMapper._assertNotNull(ObjectMapper.java:4693)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3401)
    at in.nobroker.hood.crm.entity.HashMapConverter.convertToEntityAttribute(HashMapConverter.java:31)
    at in.nobroker.hood.crm.entity.HashMapConverter.convertToEntityAttribute(HashMapConverter.java:10)
    at org.hibernate.metamodel.model.convert.internal.JpaAttributeConverterImpl.toDomainValue(JpaAttributeConverterImpl.java:45)
    at org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter$2.doConversion(AttributeConverterSqlTypeDescriptorAdapter.java:140)
    ... 186 common frames omitted

原因分析

错误根源是HashMapConverter的convertToEntityAttribute方法接收到的参数s为null,直接传入Jackson的readValue方法触发非空校验异常。

Spring Boot 1.3.0.RELEASE对应的Hibernate版本较1.2.1升级后,对AttributeConverter的null值处理逻辑发生变化:旧版本中数据库字段为null时,会跳过转换器直接返回null;新版本则会调用转换器并传入null,而当前转换器未处理null参数的情况,导致报错。

解决办法

修改HashMapConverter,在两个转换方法中先对null参数进行判断处理:

@Slf4j
public class HashMapConverter implements AttributeConverter<Map<String, Object>, String> {
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public String convertToDatabaseColumn(Map<String, Object> stringObjectMap) {
        if (stringObjectMap == null) {
            return null;
        }
        try {
            return objectMapper.writeValueAsString(stringObjectMap);
        } catch (final JsonProcessingException e) {
            log.error("JSON writing error", e);
            return null;
        }
    }

    @Override
    public Map<String, Object> convertToEntityAttribute(String s) {
        if (s == null || s.isEmpty()) {
            return null; // 或返回new HashMap<>(),根据业务需求选择
        }
        try {
            return objectMapper.readValue(s, Map.class);
        } catch (final IOException e) {
            log.error("JSON reading error", e);
            return null;
        }
    }
}

额外优化(可选)

如果需要更严谨的类型转换,可将Map.class替换为TypeReference,避免Jackson将数值等类型转为非预期的LinkedHashMap:

return objectMapper.readValue(s, new TypeReference<Map<String, Object>>() {});

内容的提问来源于stack exchange,提问作者Durgesh Soni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 06:36:19