MapStruct跨包引用DateMapper时映射失效,报Instant转LocalDateTime错误
问题根本原因
两种包结构的运行差异完全来自Java的访问权限规则:
- 你定义的
DateMapper类中,两个类型转换方法都没有显式添加public修饰符,属于包私有访问权限,仅能被当前包内的类直接调用。 - 当
DateMapper和CarMapper同属de.zinnchen.mapper.a包时,MapStruct注解处理器能正常扫描到同包下的这两个转换方法,生成的实现代码可以直接调用方法、完成类型转换。 - 当把
DateMapper拆分到de.zinnchen.mapper.b包后,位于a包的CarMapper及其生成实现代码,按照Java访问规则无法跨包调用b包中的包私有方法。MapStruct在编译期识别不到可用的类型转换逻辑,就会抛出“Can't map property”的编译错误。
可落地的解决方案
两种修改方式任选其一即可,不需要调整现有包结构:
方案1:调整DateMapper的方法访问权限
给DateMapper中的两个转换方法添加public修饰符,让跨包代码可以正常访问:
package de.zinnchen.mapper.b; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; public class DateMapper { public LocalDateTime instantToLocalDateTime(Instant instant) { return instant .atZone(ZoneId.of("UTC")) .toLocalDateTime(); } public Instant LocalDateTimeToInstant(LocalDateTime localDateTime) { return localDateTime.toInstant(ZoneOffset.UTC); } }
修改后MapStruct会正常识别这两个跨包可见的方法,生成的实现代码和同包场景下的逻辑完全一致。
方案2:将DateMapper改为标准MapStruct Mapper接口
如果要符合MapStruct的通用使用规范,可以把DateMapper定义为带@Mapper注解的接口,利用接口方法默认的public权限规避跨包访问问题:
package de.zinnchen.mapper.b; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; @Mapper public interface DateMapper { DateMapper INSTANCE = Mappers.getMapper(DateMapper.class); default LocalDateTime instantToLocalDateTime(Instant instant) { return instant .atZone(ZoneId.of("UTC")) .toLocalDateTime(); } default Instant LocalDateTimeToInstant(LocalDateTime localDateTime) { return localDateTime.toInstant(ZoneOffset.UTC); } }
补充说明
之前同包结构下能正常运行,本质是因为没有触发跨包访问的权限校验:同包下的包私有方法可以自由调用,MapStruct生成的new DateMapper()、直接调用方法的代码可以正常编译。一旦拆分到独立包,Java的访问控制规则就会生效,非public修饰的方法根本不具备被跨包调用的资格,自然会导致映射逻辑失效。
内容的提问来源于stack exchange,提问作者zinnchen
相关产品推荐
相关产品推荐

