如何内省通过@JsonNaming显式设置的Java类Jackson PropertyNamingStrategy?
解决方案
当然可以通过内省目标类或Jackson自带的API获取@JsonNaming注解指定的命名策略,完全不用调用方额外处理字段映射细节。下面是具体实现方案:
1. 读取目标类的命名策略
直接通过反射获取类上的@JsonNaming注解,实例化对应的策略类即可:
import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; import com.fasterxml.jackson.databind.PropertyNamingStrategies; private PropertyNamingStrategy getNamingStrategy(Class<?> targetClass) { // 提取类上的@JsonNaming注解 JsonNaming classNaming = targetClass.getAnnotation(JsonNaming.class); if (classNaming == null) { // 无注解时用Jackson默认策略 return PropertyNamingStrategies.DEFAULT; } Class<? extends PropertyNamingStrategy> strategyClass = classNaming.value(); try { // 内置策略优先用单例实例,避免重复初始化 if (PropertyNamingStrategies.NamingBase.class.isAssignableFrom(strategyClass)) { return ((PropertyNamingStrategies.NamingBase) strategyClass.getDeclaredConstructor().newInstance()); } return strategyClass.getDeclaredConstructor().newInstance(); } catch (ReflectiveOperationException e) { throw new IllegalArgumentException("无法初始化类[" + targetClass.getName() + "]的命名策略", e); } }
2. 转换数据库字段名并反序列化
拿到命名策略后,把数据库返回的字段名转换成符合目标类属性规则的键,再用ObjectMapper反序列化:
import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Map; public <T> T dbRowToObject(Map<String, Object> dbRow, Class<T> targetClass, ObjectMapper objectMapper) { PropertyNamingStrategy strategy = getNamingStrategy(targetClass); Map<String, Object> convertedMap = new HashMap<>(dbRow.size()); // 遍历数据库字段,用命名策略转换键名(这里适配大小写差异,先转小写再处理) for (Map.Entry<String, Object> entry : dbRow.entrySet()) { String convertedKey = strategy.nameForField(null, null, entry.getKey().toLowerCase()); convertedMap.put(convertedKey, entry.getValue()); } // 反序列化到目标对象 try { return objectMapper.convertValue(convertedMap, targetClass); } catch (Exception e) { throw new RuntimeException("数据库行转对象失败", e); } }
3. 更简洁的方式:利用Jackson的ObjectReader
Jackson的ObjectReader会自动识别类上的@JsonNaming注解,无需手动转换字段名——如果你的数据库字段和策略对应的格式仅大小写不同,可以直接开启大小写不敏感匹配:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; public <T> T dbRowToObject(Map<String, Object> dbRow, Class<T> targetClass, ObjectMapper objectMapper) { ObjectReader reader = objectMapper.readerFor(targetClass) // 开启大小写不敏感匹配,适配数据库字段和策略的大小写差异 .with(com.fasterxml.jackson.databind.DeserializationFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES); try { return reader.convertValue(dbRow, targetClass); } catch (Exception e) { throw new RuntimeException("数据库行转对象失败", e); } }
这样调用方只需要传入数据库行的Map、目标类和ObjectMapper,完全不用关心命名策略的细节。
内容的提问来源于stack exchange,提问作者Rich
相关产品推荐
相关产品推荐

