在最新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
相关产品推荐
相关产品推荐

