lombok源码学习

828 阅读3分钟

projectlombok.org/ 版本 1.18.23

查看ant版本 D:\git\lombok\buildScripts\setup.ant.xml,已经提示ant需要至少1.10.9,jdk必须jdk11以上才能编译

	<fail>ant needs to be at least v1.10.0 or higher to build lombok. Your version is: ${ant.version}
		<condition>
			<not><antversion atleast="1.10.0" /></not>
		</condition>
	</fail>
	<fail>lombok must be compiled on jdk11 or later. Your version is: ${ant.java.version}
		<condition>
			<not><matches string="${ant.java.version}" pattern="${pattern.jdk11plus}" /></not>
		</condition>
	</fail>

设置ant环境变量,jdk环境变量,运行即可查看,操作步骤,写得很详细。

D:\git\lombok>ant
Buildfile: D:\git\lombok\build.xml

quickstart:
     [echo]
     [echo] Dear contributor,
     [echo]
     [echo] For full instructions and information on what this project contains, run:
     [echo]
     [echo]   > ant help
     [echo]
     [echo] If you want to get started quickly:
     [echo]
     [echo] 1. Run `ant eclipse`.
     [echo] 2. Start up eclipse (https://www.eclipse.org/).
     [echo] 3. In the menu: File > Import... > Existing Project Into Workspace
     [echo] 4. Browse to this directory and import it:
     [echo]  (D:\git\lombok)
     [echo] 5. In eclipse: Run > Debug configurations... >
     [echo]   then pick one of the configs named `Lombok test`.
     [echo] 6. Run `ant dist`.
     [echo]
     [echo] Have fun!

BUILD SUCCESSFUL
Total time: 0 seconds

D:\git\lombok>

用eclipse调试一个,就用自带的 D:\git\lombok\test\transform\src\lombok\transform\TestWithDelombok.java

test/transform/resource/before这里面类太多了, image.png

就用这个,这个简单

class AccessorsMakeFinalLombokConfig {
	@lombok.Setter
	private String test;
}

D:\git\lombok\test\core\src\lombok\DirectoryRunner.java这个accept方法改一下,只调试一个简单的类

private static final FileFilter JAVA_FILE_FILTER = new FileFilter() {
		@Override public boolean accept(File file) {
			if(file.getName().equals("AccessorsMakeFinalLombokConfig.java")) {
				return true;
			}
			return false;
//			if (!file.isFile() || !file.getName().endsWith(".java")) return false;
//			boolean positiveFilter = false;
//			for (String dfof : DEBUG_FOCUS_ON_FILE) {
//				if (dfof.isEmpty()) continue;
//				if (!dfof.endsWith(".java")) dfof = dfof + ".java";
//				boolean invert = dfof.startsWith("!");
//				if (invert) dfof = dfof.substring(1);
//				positiveFilter = positiveFilter || !invert;
//				int starIdx = dfof.indexOf('*');
//				if (starIdx == -1) {
//					if (file.getName().equals(dfof)) return !invert;
//				} else {
//					if (file.getName().startsWith(dfof.substring(0, starIdx)) && file.getName().endsWith(dfof.substring(starIdx + 1))) return !invert;
//				}
//			}
//			return !positiveFilter;
		}
	};

调试一下,decl就是set方法

image.png

记录一下调试的调用

Thread [main] (Suspended)	
	HandleSetter.createSetterWithRecv(long, boolean, JavacNode, JavacTreeMaker, String, Name, Name, JCExpression, JCStatement, JavacNode, List<JCAnnotation>, List<JCAnnotation>, JCVariableDecl) line: 289	
	HandleSetter.createSetter(long, boolean, JavacNode, JavacTreeMaker, String, Name, Name, JCExpression, JCStatement, JavacNode, List<JCAnnotation>, List<JCAnnotation>) line: 222	
	HandleSetter.createSetter(long, boolean, JavacNode, JavacTreeMaker, String, Name, Name, boolean, JavacNode, List<JCAnnotation>, List<JCAnnotation>) line: 205	
	HandleSetter.createSetter(long, JavacNode, JavacTreeMaker, JavacNode, List<JCAnnotation>, List<JCAnnotation>) line: 192	
	HandleSetter.createSetterForField(AccessLevel, JavacNode, JavacNode, boolean, List<JCAnnotation>, List<JCAnnotation>) line: 184	
	HandleSetter.createSetterForFields(AccessLevel, Collection<JavacNode>, JavacNode, boolean, List<JCAnnotation>, List<JCAnnotation>) line: 140	
	HandleSetter.handle(AnnotationValues<Setter>, JCAnnotation, JavacNode) line: 130	
	HandlerLibrary$AnnotationHandlerContainer<T>.handle(JavacNode) line: 113	
	HandlerLibrary.handleAnnotation(JCTree$JCCompilationUnit, JavacNode, JCTree$JCAnnotation, long) line: 256	
	JavacTransformer$AnnotationVisitor.visitAnnotationOnField(JCTree$JCVariableDecl, JavacNode, JCTree$JCAnnotation) line: 84	
	JavacNode.traverse(JavacASTVisitor) line: 135	
	JavacAST.traverseChildren(JavacASTVisitor, JavacNode) line: 222	
	JavacNode.traverse(JavacASTVisitor) line: 100	
	JavacAST.traverseChildren(JavacASTVisitor, JavacNode) line: 222	
	JavacNode.traverse(JavacASTVisitor) line: 95	
	JavacAST.traverseChildren(JavacASTVisitor, JavacNode) line: 222	
	JavacNode.traverse(JavacASTVisitor) line: 90	
	JavacAST.traverse(JavacASTVisitor) line: 218	
	JavacTransformer.transform(long, Context, List<JCCompilationUnit>, CleanupRegistry) line: 63	
	LombokProcessor.process(Set<TypeElement>, RoundEnvironment) line: 328	
	JavacProcessingEnvironment.callProcessor(Processor, Set<TypeElement>, RoundEnvironment) line: 1023	
	JavacProcessingEnvironment.discoverAndRunProcs(Set<TypeElement>, List<ClassSymbol>, List<PackageSymbol>, List<ModuleSymbol>) line: 939	
	JavacProcessingEnvironment$Round.run(boolean, boolean) line: 1267	
	JavacProcessingEnvironment.doProcessing(List<JCCompilationUnit>, List<ClassSymbol>, Iterable<PackageSymbol>, DeferredDiagnosticHandler) line: 1382	
	JavaCompiler.processAnnotations(List<JCCompilationUnit>, Collection<String>) line: 1234	
	Delombok.delombok() line: 788	
	RunTestsViaDelombok.transformCode(Collection<CompilerMessage>, StringWriter, File, String, Map<String,String>, int, boolean) line: 93	
	AbstractRunTests$1.runTest() line: 97	
	DirectoryRunner.run(RunNotifier) line: 170	
	JUnit4TestReference.run(TestExecution) line: 93	
	TestExecution.run(ITestReference[]) line: 40	
	RemoteTestRunner.runTests(String[], String, TestExecution) line: 529	
	RemoteTestRunner.runTests(TestExecution) line: 756	
	RemoteTestRunner.run() line: 452	
	RemoteTestRunner.main(String[]) line: 210

D:\git\lombok\test\core\src\lombok\AbstractRunTests.java expected和actualFile是否一致。

	private void compare(String name, LombokTestSource expected, String actualFile, LinkedHashSet<CompilerMessage> actualMessages, boolean printErrors, boolean skipCompareContent) throws Throwable {
		if (!skipCompareContent) try {
			compareContent(name, expected.getContent(), actualFile);
		} catch (Throwable e) {
			if (printErrors) {
				System.out.println("***** " + name + " *****");
				System.out.println(e.getMessage());
				System.out.println("**** Expected ******");
				System.out.println(expected.getContent());
				System.out.println("****  Actual  ******");
				System.out.println(actualFile);
				if (actualMessages != null && !actualMessages.isEmpty()) {
					System.out.println("**** Actual Errors *****");
					for (CompilerMessage actualMessage : actualMessages) {
						System.out.println(actualMessage);
					}
				}
				System.out.println("*******************");
			}
			if (dumpActualFilesHere != null) {
				dumpToFile(new File(dumpActualFilesHere, name), actualFile);
			}
			throw e;
		}
		
		try {
			compareMessages(name, expected.getMessages(), actualMessages);
		} catch (Throwable e) {
			if (printErrors) {
				System.out.println("***** " + name + " *****");
				System.out.println(e.getMessage());
				System.out.println("**** Expected ******");
				for (CompilerMessageMatcher expectedMessage : expected.getMessages()) {
					System.out.println(expectedMessage);
				}
				System.out.println("****  Actual  ******");
				for (CompilerMessage actualMessage : actualMessages) {
					System.out.println(actualMessage);
				}
				System.out.println("****  Actual File  ******");
				System.out.println(lineNumber(actualFile));
				System.out.println("*******************");
			}
			if (dumpActualFilesHere != null) {
				dumpToFile(new File(dumpActualFilesHere, name + ".messages"), actualMessages);
			}
			throw e;
		}
	}

expected就是getAfterDirectory()里面写好的文件。

/*
 * Copyright (C) 2009-2021 The Project Lombok Authors.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package lombok.transform;

import java.io.File;

import lombok.DirectoryRunner;

import org.junit.runner.RunWith;

@RunWith(DirectoryRunner.class)
public class TestWithDelombok extends DirectoryRunner.TestParams {
	@Override
	public DirectoryRunner.Compiler getCompiler() {
		return DirectoryRunner.Compiler.DELOMBOK;
	}
	
	@Override
	public boolean printErrors() {
		return true;
	}
	
	@Override
	public File getBeforeDirectory() {
		return new File("test/transform/resource/before");
	}
	
	@Override
	public File getAfterDirectory() {
		return new File("test/transform/resource/after-delombok");
	}
	
	@Override
	public File getMessagesDirectory() {
		return new File("test/transform/resource/messages-delombok");
	}
	
	@Override
	public boolean expectChanges() {
		return true;
	}
	
	@Override public String testNamePrefix() {
		return "javac-";
	}
}

这个只调试了一个setter,如下图还有很多。常用的HandlerData可以再里面设置断点,自己调试。

image.png