lombok与mapstruct冲突的问题

现象
在生成的mapper方法中,没有调用实体类的getter和setter
ebaee674a421ffad5b74f3872192c28f

解决方案

配置plugin时需要加入lombok-mapstruct-binding依赖

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-compiler-plugin</artifactId>
	<configuration>
		<source>${java.version}</source>
		<target>${java.version}</target>
		<encoding>${project.build.sourceEncoding}</encoding>
		<annotationProcessorPaths>
			<path>
				<groupId>org.mapstruct</groupId>
				<artifactId>mapstruct-processor</artifactId>
				<version>${org.mapstruct.version}</version>
			</path>
			<path>
				<groupId>org.projectlombok</groupId>
				<artifactId>lombok</artifactId>
				<version>${lombok.version}</version>
			</path>

			<!-- additional annotation processor required as of Lombok 1.18.16 -->
			<path>
				<groupId>org.projectlombok</groupId>
				<artifactId>lombok-mapstruct-binding</artifactId>
				<version>0.2.0</version>
			</path>
		</annotationProcessorPaths>
	</configuration>
</plugin>

原因分析
lombok基于AST(抽象语法树)修改实现。
mapstruct基于生成代码文件实现。
实体类中使用了lombok注解,mapstruct需要在lombok的AST(抽象语法树)修改完成之后生成代码文件才行。
lombok-mapstruct-binding定义了事件通知器,在lombok修改完成后才会开始执行mapstruct的处理。
代码分析

class NotifierHider {
	
	public static class AstModificationNotifier implements AstModifyingAnnotationProcessor {
		private static Field lombokInvoked;
		
		//该方法判断lombok的处理是否完成
		@Override public boolean isTypeComplete(TypeMirror type) {
			if (System.getProperty("lombok.disable") != null) return true;
			return isLombokInvoked();
		}
		
		private static boolean isLombokInvoked() {
			if (lombokInvoked != null) {
				try {
					return lombokInvoked.getBoolean(null);
				} catch (Exception e) {}
				return true;
			}
			
			try {
				Class<?> data = Class.forName("lombok.launch.AnnotationProcessorHider$AstModificationNotifierData");
				lombokInvoked = data.getField("lombokInvoked");
				return lombokInvoked.getBoolean(null);
			} catch (Exception e) {}
			return true;
		}
	}
}

在mapstruct 注解解析器生成mapper代码时会调用org.mapstruct.ap.internal.model.common.TypeFactory#canBeProcessed
来判断lombok是否处理完成,如果未处理完成会抛出TypeHierarchyErroneousException异常,代码如下:

if ( !canBeProcessed( mirror ) ) {
	throw new TypeHierarchyErroneousException( mirror );
}

在代码外层捕获到这个异常后会进行如下操作:

try {
  //省略,处理mapper代码的生成
}
catch ( TypeHierarchyErroneousException thie ) {
	TypeMirror erroneousType = thie.getType();
	Element erroneousElement = erroneousType != null ? roundContext.getAnnotationProcessorContext()
		.getTypeUtils()
		.asElement( erroneousType ) : null;
	if ( options.isVerbose() ) {
		processingEnv.getMessager().printMessage(
			Kind.NOTE, "MapStruct: referred types not available (yet), deferring mapper: "
				+ mapperElement );
	}
	deferredMappers.add( new DeferredMapper( mapperElement, erroneousElement ) );
}

将未处理的mapper放入deferredMappers集合中,在processor的下一轮process时会处理deferredMappers中的元素。

posted @ 2025-09-19 14:23  Hekk丶  阅读(8)  评论(0)    收藏  举报