I wanted to write a simple eclipse plugin to “Lombok classes”

Motivations

Lombok is a great project.
It allow java developper to write simpler code (small is beautifull), as in C#, Groovy, Kotlin BUT without switching to C#, Groovy, Kotlin…

https://projectlombok.org/

As as additional motivation, it is a subject I have just proposed to Devoxx France 2017 "Call For Paper".


Steps for using the magic "Lomboker eclipse plugin"

Images worth thousands words.
Here is how to use it.
Select either Java Project(s), Java Package(s) or Java class(es), and right click for refactoring menu action: "recursive Lomboker"

Choose some settings (currently supports only @Getter / @Setter refactoring)

Click on Preview, then Ok

And here you are!

How it work

Come to Devoxx France 2017, if hopefully this talk will be selected.
Source code is extremely simple...
It is open-source, see here: https://github.com/Arnaud-Nauwynck/mytoolbox .. fr.an.eclipse.tools.lombok
There is some boiler-plate... not very interresting to detail. (dependency to other plugins fr.an.eclipse.pattern, etc.)
Basically, it allows to handle user selection and recurse on each *.java file, then call the magic Lomboker transformation on each parsed AST, and save it back to java file.
The first code I wrote took me ~2 hours, for detecting getter/setter methods and changing them to @Getter and @Setter.
It is very simple, representing ~90 lines of AST tree manipulation in eclipse.
Here is and extract of the code:
private static final String LOMBOK_PACKAGE = "lombok";
private static final String ANNOTATION_LOMBOK_GETTER_SIMPLENAME = "Getter";
private static final String ANNOTATION_LOMBOK_SETTER_SIMPLENAME = "Setter";

protected static class FieldGetterSetterDetection {
	final String fieldName;
	VariableDeclarationFragment fieldDecl;
	MethodDeclaration getterDecl;
	MethodDeclaration setterDecl;
	
	public FieldGetterSetterDetection(String fieldName) {
		this.fieldName = fieldName;
	}
}

@Override
protected void doRefactorUnit(CompilationUnit unit, Object refactoringInfoObject) {
	if (useGetterSetter) {
		doRefactorUnit_GetterSetter(unit);
	}
}

protected void doRefactorUnit_GetterSetter(CompilationUnit unit) {
	ASTVisitor vis = new ASTVisitor() {
		@Override
		public boolean visit(TypeDeclaration node) {
			doVisitRefactorGetterSetter(unit, node);
			return super.visit(node);
		}
	};
	unit.accept(vis);
}

private void doVisitRefactorGetterSetter(CompilationUnit unit, TypeDeclaration node) {
	List<BodyDeclaration> decls = node.bodyDeclarations();
	Map<String,FieldGetterSetterDetection> fieldInfos = new HashMap<>();
	// scan methods, detect getter/setter
	for(BodyDeclaration decl : decls) {
		if (decl instanceof MethodDeclaration) {
			MethodDeclaration m = (MethodDeclaration) decl;
			String methName = m.getName().getIdentifier();
			if (methName.startsWith("get") || methName.startsWith("is")) {
				String propName = MatchASTUtils.matchBasicGetterMeth(m);
				if (propName != null) {
					FieldGetterSetterDetection fo = getOrCreateField(fieldInfos, propName);
					fo.getterDecl = m;
				}
			} else if (methName.startsWith("set")) {
				String propName = MatchASTUtils.matchBasicSetterMeth(m);
				if (propName != null) {
					FieldGetterSetterDetection fo = getOrCreateField(fieldInfos, propName);
					fo.setterDecl = m;
				}
			}
		}
	}
	// scan fields, lookup corresponding getter/setter
	for(BodyDeclaration decl : decls) {
		if (decl instanceof FieldDeclaration) {
			FieldDeclaration f = (FieldDeclaration) decl;
			List<VariableDeclarationFragment> fieldDecls = f.fragments();
			if (fieldDecls.size() != 1) {
				continue; // unsupported yet! "private Type x, y;" ... only "private Type x;"
			}
			for(VariableDeclarationFragment fieldDecl : fieldDecls) {
				String fieldName = fieldDecl.getName().getIdentifier();
				FieldGetterSetterDetection fo = fieldInfos.get(fieldName);
				if (fo != null) {
					fo.fieldDecl = fieldDecl;
					
					if (fo.setterDecl != null) {
						// refactor: add lombok annotation @Setter .. delete setter method
						JavaASTUtil.addMarkerAnnotation(unit, f.modifiers(), 
								LOMBOK_PACKAGE, ANNOTATION_LOMBOK_SETTER_SIMPLENAME);
						fo.setterDecl.delete();
					}
					if (fo.getterDecl != null) {
						// refactor: add lombok annotation @Getter .. delete getter method
						JavaASTUtil.addMarkerAnnotation(unit, f.modifiers(), 
								LOMBOK_PACKAGE, ANNOTATION_LOMBOK_GETTER_SIMPLENAME);
						fo.getterDecl.delete();
					}
				}							
			}
		}
	}
}

protected static FieldGetterSetterDetection getOrCreateField(Map<String,FieldGetterSetterDetection> fieldInfos, String name) {
	FieldGetterSetterDetection res = fieldInfos.get(name);
	if (res == null) {
		res = new FieldGetterSetterDetection(name);
		fieldInfos.put(name, res);
	}
	return res;
}

Day 2 ... see next post : Lomboker Eclipse Plugin (Day 2)