MapStruct自定义命名策略实现前缀字段自动映射遇null问题
MapStruct自定义命名策略实现带前缀实体与DTO自动映射问题排查
问题背景
实体类字段带固定前缀(如UserEntity的usrName、usrEmail),DTO类对应字段无前缀(name、email),希望通过MapStruct全局自定义命名策略替代@Mapping注解实现自动映射,但配置后DTO所有字段均为null,与预期不符。
已实现配置
1. Maven pom.xml配置片段
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>17</source> <target>17</target> <annotationProcessorPaths> <!-- MapStruct Processor --> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.4.1.Final</version> </path> <!-- Lombok --> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> </path> </annotationProcessorPaths> <compilerArgs> <arg>-Amapstruct.accessorNamingStrategy=com.mypackage.CustomAccessorNamingStrategy</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
2. 自定义命名策略类
import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy; import javax.lang.model.element.ExecutableElement; import org.mapstruct.ap.internal.util.IntrospectorUtils; public class CustomAccessorNamingStrategy extends DefaultAccessorNamingStrategy { @Override public String getPropertyName(ExecutableElement getterOrSetterMethod) { String originalPropertyName = super.getPropertyName(getterOrSetterMethod); if (originalPropertyName.startsWith("usr")) { return IntrospectorUtils.decapitalize(originalPropertyName.substring(3)); } return originalPropertyName; } }
3. Mapper接口与测试代码
import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); UserDTO toDTO(UserEntity userEntity); }
import org.springframework.stereotype.Service; @Service public class UserService { public void exampleUsage() { UserEntity userEntity = new UserEntity(); userEntity.setUsrName("John Doe"); userEntity.setUsrEmail("john@example.com"); userEntity.setUsrAddress("123 Main St"); userEntity.setUsrAge("30"); UserDTO userDTO = UserMapper.INSTANCE.toDTO(userEntity); System.out.println("Mapped to DTO: " + userDTO); } }
预期结果:Mapped to DTO: UserDTO{name='John Doe', email='john@example.com', address='123 Main St', age='30'}
实际结果:Mapped to DTO: UserDTO{name=null, email=null, address=null, age=null}
问题原因排查
- Lombok与MapStruct协同问题:MapStruct无法正确识别Lombok生成的getter/setter方法,导致无法读取实体类字段值。
- 自定义策略类加载失败:编译参数中指定的策略类包路径错误,或MapStruct 1.4.1.Final版本对SPI支持存在兼容性问题。
- 编译顺序问题:自定义策略类未在MapStruct注解处理器执行前完成编译,导致处理器无法加载该类。
解决方法
1. 完善编译参数,确保Lombok与MapStruct兼容
在compilerArgs中添加Lombok支持参数,同时开启调试日志便于排查:
<compilerArgs> <arg>-Amapstruct.accessorNamingStrategy=com.mypackage.CustomAccessorNamingStrategy</arg> <arg>-Amapstruct.lombok.addon=true</arg> <arg>-Amapstruct.verbose=true</arg> </compilerArgs>
2. 验证并修正策略类包路径
确认-Amapstruct.accessorNamingStrategy指定的类全限定名与实际代码完全一致,比如策略类在com.example.mapper下,则参数应为com.example.mapper.CustomAccessorNamingStrategy。
3. 升级MapStruct至稳定版本
将MapStruct版本升级到1.5.5.Final或更高版本,新版本对SPI实现和Lombok兼容性更优:
<path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.5.Final</version> </path>
4. 调试自定义策略执行逻辑
在策略类中添加日志打印,确认属性转换逻辑是否执行:
import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy; import javax.lang.model.element.ExecutableElement; import org.mapstruct.ap.internal.util.IntrospectorUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CustomAccessorNamingStrategy extends DefaultAccessorNamingStrategy { private static final Logger logger = LoggerFactory.getLogger(CustomAccessorNamingStrategy.class); @Override public String getPropertyName(ExecutableElement getterOrSetterMethod) { String originalPropertyName = super.getPropertyName(getterOrSetterMethod); logger.debug("Original property name from getter/setter: {}", originalPropertyName); if (originalPropertyName.startsWith("usr")) { String convertedName = IntrospectorUtils.decapitalize(originalPropertyName.substring(3)); logger.debug("Converted property name: {}", convertedName); return convertedName; } return originalPropertyName; } }
5. 重新编译并验证
执行mvn clean compile查看编译日志,确认自定义策略类已加载且属性转换逻辑正常执行,再运行测试代码验证映射结果。
内容的提问来源于stack exchange,提问作者yeye
相关产品推荐
相关产品推荐

