package com.mhd.springbootinit.utils;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @Description:
* @title: ConvertUtil
* @Author mhd
* @Date: 2025/4/15 22:08
* @Version 1.0
*/
@Slf4j
public class ConvertUtil {
private static final ObjectMapper objectMapper = new ObjectMapper();
static {
// 允许访问私有字段
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
// 忽略未知属性
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 启用不区分大小写的属性匹配
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
}
/**
* 将 List<Map<String, Object>> 映射到实体类的List
* @param mapList
* @param clazz
* @return
* @param <T>
*/
public static <T> List<T> convertMapListToObjectList(List<Map<String, Object>> mapList, Class<T> clazz) {
List<T> res = new ArrayList<>();
ObjectMapper mapper = new ObjectMapper();
// 启用不区分大小写的属性匹配
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
for (Map<String, Object> map : mapList) {
try {
T instance = mapper.convertValue(map, clazz);
res.add(instance);
} catch (IllegalArgumentException e) {
// 处理转换异常
e.printStackTrace();
}
}
return res;
}
}
@SpringBootTest
public class Test01 {
@Test
void test02() {
List<Map<String, Object>> mapList = new ArrayList<>();
Map<String, Object> map = new HashMap<>();
map.put("SEC_CODE", "testName");
map.put("A_COUNT", 1);
map.put("ID", 1);
mapList.add(map);
List<UserTestVO> userList = ConvertUtil.convertMapListToObjectList(mapList, UserTestVO.class);
}
}
由于查到的原始数据的字段名是确定了的,大小写固定的,但是我们要转换的目标类 ClassMap
中的键不匹配。
@Test
void test02() {
List<Map<String, Object>> mapList = new ArrayList<>();
Map<String, Object> map = new HashMap<>();
map.put("SEC_CODE", "testName");
map.put("A_COUNT", 1);
map.put("ID", 1);
mapList.add(map);
List<UserTestVO> userList = ConvertUtil.convertMapListToObjectList(mapList, UserTestVO.class);
}
@Data
public class UserTestVO implements Serializable {
private static final long serialVersionUID = 7004030192266543336L;
/**
* id
*/
private Long ID;
/**
* 用户昵称
*/
private String USER_NAME;
private String SEC_CODE;
private Integer A_COUNT;
}
java.lang.IllegalArgumentException: Unrecognized field "SEC_CODE" (class com.mhd.springbootinit.model.vo.UserTestVO), not marked as ignorable (4 known properties: "a_COUNT", "id", "user_NAME", "sec_CODE"])
at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: com.mhd.springbootinit.model.vo.UserTestVO["SEC_CODE"])
at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4393)
at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:4324)
at com.mhd.springbootinit.utils.ConvertUtil.convertMapListToObjectList(ConvertUtil.java:24)
at com.mhd.springbootinit.Test01.test02(Test01.java:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "SEC_CODE" (class com.mhd.springbootinit.model.vo.UserTestVO), not marked as ignorable (4 known properties: "a_COUNT", "id", "user_NAME", "sec_CODE"])
at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: com.mhd.springbootinit.model.vo.UserTestVO["SEC_CODE"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:1127)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:2023)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1700)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1678)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:319)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176)
at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4388)
... 72 more
要解决将 Map
转换为对象时出现的字段无法识别问题,需确保字段名称正确映射。
Jackson 在反序列化时默认使用 getter/setter 方法推断属性名,导致字段名与 Map
中的键不匹配。例如,SEC_CODE
字段生成的 getter 为 getSEC_CODE()
,Jackson 可能将其属性名视为 sec_CODE
,而 Map
中的键为 SEC_CODE
,导致不匹配。
@JsonProperty
注解在 UserTestVO
的字段上添加 @JsonProperty
注解,明确指定 JSON 字段名。
@Data
public class UserTestVO implements Serializable {
private static final long serialVersionUID = 7004030192266543336L;
@JsonProperty("ID")
private Long ID;
@JsonProperty("USER_NAME")
private String USER_NAME;
@JsonProperty("SEC_CODE")
private String SEC_CODE;
@JsonProperty("A_COUNT")
private Integer A_COUNT;
}
修改 ConvertUtil
中的 ObjectMapper
配置,使其直接使用字段名并忽略大小写敏感。
public class ConvertUtil {
private static final ObjectMapper objectMapper = new ObjectMapper();
static {
// 允许访问私有字段
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
// 忽略未知属性
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 启用不区分大小写的属性匹配
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
}
public static <T> List<T> convertMapListToObjectList(List<Map<String, Object>> mapList, Class<T> clazz) {
return mapList.stream()
.map(map -> objectMapper.convertValue(map, clazz))
.collect(Collectors.toList());
}
}
选择其中一种方法即可解决问题。推荐使用 方法 1,因为它更明确且不易受全局配置影响。