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

在最新Spring Boot与Jackson环境下,如何转换数字开头键的JSON为POJO?

不用@JsonProperty,处理数字开头JSON键的POJO转换方案

针对JSON字段以数字开头(如"11var")、Java变量不能数字开头的场景,在最新Spring Boot + Jackson环境下,有以下几种替代方案:

方案一:自定义命名策略(推荐,强类型)

通过自定义Jackson的命名策略,自动完成JSON字段名到合法Java变量名的映射,无需逐个加注解。

步骤1:编写自定义命名策略类

根据需求选择转换规则,比如给数字开头的字段加下划线前缀(最简单),或者把数字转成英文单词(更规范)。

示例1:加下划线前缀的策略

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;

public class NumberPrefixNamingStrategy extends PropertyNamingStrategy {
    @Override
    public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
        // Java变量名转JSON字段名:去掉开头的下划线
        if (defaultName.startsWith("_") && defaultName.length() > 1 && Character.isDigit(defaultName.charAt(1))) {
            return defaultName.substring(1);
        }
        return defaultName;
    }

    @Override
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
        return processGetterSetter(defaultName);
    }

    @Override
    public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
        return processGetterSetter(defaultName);
    }

    private String processGetterSetter(String defaultName) {
        // 处理getter/setter对应的JSON字段名
        if (defaultName.startsWith("_") && defaultName.length() > 1 && Character.isDigit(defaultName.charAt(1))) {
            return defaultName.substring(1);
        }
        return defaultName;
    }
}

示例2:数字转英文单词的策略(更规范)

如果想让Java变量名更易读,可以把开头的数字转成英文单词,比如"11var"对应elevenVar:

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;

import java.util.Map;

public class NumberToWordNamingStrategy extends PropertyNamingStrategy {
    // 维护数字到英文单词的映射,按需扩展
    private static final Map<String, String> NUMBER_MAP = Map.of(
            "11", "eleven",
            "2", "two",
            "3", "three"
    );

    @Override
    public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
        // Java变量名转JSON字段名:把开头的英文单词转回数字
        for (Map.Entry<String, String> entry : NUMBER_MAP.entrySet()) {
            if (defaultName.startsWith(entry.getValue()) && defaultName.length() > entry.getValue().length()) {
                char nextChar = defaultName.charAt(entry.getValue().length());
                if (Character.isUpperCase(nextChar)) {
                    return entry.getKey() + Character.toLowerCase(nextChar) + defaultName.substring(entry.getValue().length() + 1);
                }
            }
        }
        return defaultName;
    }

    @Override
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
        return processGetterSetter(defaultName);
    }

    @Override
    public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
        return processGetterSetter(defaultName);
    }

    private String processGetterSetter(String defaultName) {
        // 处理getter/setter对应的JSON字段名,逻辑同nameForField
        for (Map.Entry<String, String> entry : NUMBER_MAP.entrySet()) {
            if (defaultName.startsWith(entry.getValue()) && defaultName.length() > entry.getValue().length()) {
                char nextChar = defaultName.charAt(entry.getValue().length());
                if (Character.isUpperCase(nextChar)) {
                    return entry.getKey() + Character.toLowerCase(nextChar) + defaultName.substring(entry.getValue().length() + 1);
                }
            }
        }
        return defaultName;
    }
}

步骤2:配置命名策略

有两种配置方式:

方式A:全局生效(所有JSON转换都用这个策略)

在application.yml或application.properties中添加配置:

spring:
  jackson:
    property-naming-strategy: com.yourpackage.NumberPrefixNamingStrategy
    # 如果用数字转单词的策略,就换成com.yourpackage.NumberToWordNamingStrategy

方式B:仅针对特定POJO生效

在POJO类上添加@JsonNaming注解:

import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(NumberPrefixNamingStrategy.class)
public class MyPojo {
    // 对应JSON的"11var"
    private String _11var;
    // 对应JSON的"11var2"
    private String _11var2;
    // 对应JSON的"11var3"
    private String _11var3;

    // getter和setter方法,按正常Java规范编写即可
    public String get_11var() {
        return _11var;
    }

    public void set_11var(String _11var) {
        this._11var = _11var;
    }

    // 其他字段的getter/setter...
}

如果用数字转单词的策略,POJO的变量名就可以写成:

@JsonNaming(NumberToWordNamingStrategy.class)
public class MyPojo {
    private String elevenVar;
    private String elevenVar2;
    private String elevenVar3;

    // getter/setter
    public String getElevenVar() {
        return elevenVar;
    }

    public void setElevenVar(String elevenVar) {
        this.elevenVar = elevenVar;
    }
}

方案二:使用@JsonAnySetter/@JsonAnyGetter(适合字段不固定的场景)

如果JSON字段数量多且不确定,可以用Map来接收所有数字开头的字段,无需定义单个变量:

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;

import java.util.HashMap;
import java.util.Map;

public class MyPojo {
    private Map<String, Object> dynamicFields = new HashMap<>();

    // 自动把所有未匹配的JSON字段存入Map
    @JsonAnySetter
    public void setDynamicField(String key, Object value) {
        dynamicFields.put(key, value);
    }

    // 序列化时把Map中的字段输出为JSON的顶级字段
    @JsonAnyGetter
    public Map<String, Object> getDynamicFields() {
        return dynamicFields;
    }

    // 可以自定义getter方法方便获取特定字段
    public String get11var() {
        return (String) dynamicFields.get("11var");
    }

    public String get11var2() {
        return (String) dynamicFields.get("11var2");
    }
}

这种方式的缺点是没有强类型约束,需要手动转换字段类型,但好处是不用提前定义所有字段。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 18:01:16