Last active
August 2, 2017 13:34
-
-
Save wreulicke/8c2b4baaf92fef332f05d1eb011b1038 to your computer and use it in GitHub Desktop.
migration script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @Grapes([ | |
| @Grab(group= 'org.eclipse.jdt', module= 'org.eclipse.jdt.core', version= '3.12.3') | |
| ]) | |
| import org.eclipse.jdt.core.dom.* | |
| import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; | |
| import groovy.io.FileType | |
| import org.eclipse.jface.text.BadLocationException | |
| import org.eclipse.jface.text.Document | |
| import org.eclipse.text.edits.MalformedTreeException | |
| import org.eclipse.text.edits.TextEdit | |
| import org.eclipse.jdt.core.JavaCore | |
| import java.util.stream.Collectors | |
| class ImportRepository { | |
| AST ast | |
| List<ImportDeclaration> imports | |
| Set<ImportDeclaration> importSet | |
| Set<ImportDeclaration> staticImportSet | |
| ImportRepository(List<ImportDeclaration> imports, AST ast) { | |
| this.imports = imports | |
| Map<Boolean, Set<ImportDeclaration>> map = imports | |
| .stream().collect Collectors.groupingBy( | |
| { it.isStatic }, | |
| Collectors.toSet() | |
| ) | |
| importSet = map.get(false) ==null ? new HashSet<ImportDeclaration>() : map.get(false); | |
| staticImportSet = map.get(true) ==null ? new HashSet<ImportDeclaration>() : map.get(true) | |
| this.ast = ast | |
| } | |
| def add(String qualifiedName) { | |
| if (isAlreadyImported(qualifiedName)) return | |
| ImportDeclaration declaration = ast.newImportDeclaration() | |
| declaration.name = ast.newName(qualifiedName) | |
| imports.add(declaration) | |
| importSet += declaration | |
| return | |
| } | |
| def findIdentifier(String identifier) { | |
| importSet.stream() | |
| .filter(isImportedQualifier(getPackageName(identifier), identifier)) | |
| .findFirst() | |
| } | |
| def findStaticIdentifier(String identifier) { | |
| staticImportSet.stream() | |
| .filter( | |
| isImportedQualifier( | |
| getPackageName(identifier).flatMap(this.&getPackageName), | |
| identifier) | |
| ) | |
| .findFirst() | |
| } | |
| def isAlreadyImported(String identifier) { | |
| findIdentifier(identifier).isPresent() | |
| } | |
| def isAlreadyStaticImported(String identifier) { | |
| findStaticIdentifier(identifier).isPresent() | |
| } | |
| def isImportedQualifier(Optional<String> packageName, String identifier) { | |
| return { | |
| if (it.isOnDemand()) { | |
| packageName.isPresent() && packageName == getPackageName(it.name.fullyQualifiedName) | |
| } else { | |
| identifier == it.name.fullyQualifiedName | |
| } | |
| } | |
| } | |
| def getPackageName(String fqcn) { | |
| int index = fqcn.lastIndexOf('.') | |
| if (index > 0) { | |
| Optional.of(fqcn.substring(0, index)) | |
| } else { | |
| Optional.empty() | |
| } | |
| } | |
| } | |
| public class MemberValuePairRepository { | |
| private Map<String, MemberValuePair> map | |
| MemberValuePairRepository(List<MemberValuePair> pairs) { | |
| map = pairs.stream().reduce(new HashMap<String, MemberValuePair>(), { r, p -> | |
| r[p.name.identifier] = p | |
| r | |
| }, {r1, r2 -> | |
| r1.putAll(r2) | |
| r1 | |
| }) | |
| } | |
| def findMember(String identifier) { | |
| Optional.ofNullable(map.get(identifier)) | |
| } | |
| def findExcludeMember(String identifier) { | |
| map.entrySet().stream() | |
| .filter { | |
| it.key != identifier | |
| } | |
| .map {it.value} | |
| .collect(Collectors.toList()) | |
| } | |
| } | |
| class Migrator { | |
| private ASTParser parser | |
| Migrator() { | |
| ASTParser parser = ASTParser.newParser AST.JLS8 | |
| parser.setKind ASTParser.K_COMPILATION_UNIT | |
| Hashtable<String, String> options = JavaCore.getOptions() | |
| JavaCore.setComplianceOptions JavaCore.VERSION_1_8, options | |
| parser.setCompilerOptions options | |
| this.parser = parser | |
| } | |
| def migrate(String source) { | |
| parser.setSource source.toCharArray() | |
| def node = parser.createAST null | |
| node.recordModifications() | |
| AST ast = node.ast | |
| def repository = new ImportRepository(node.imports(), ast) | |
| node.accept new Modifier(ast, repository) | |
| def document = new Document(source) | |
| def edit = node.rewrite(document, null) | |
| edit.apply document | |
| return document.get() | |
| } | |
| } | |
| class Modifier extends ASTVisitor { | |
| AST ast | |
| ImportRepository repository | |
| def Modifier(AST ast, ImportRepository repository) { | |
| this.ast = ast | |
| this.repository = repository | |
| } | |
| def getNormalAnnotation(Object e){ | |
| if (e instanceof NormalAnnotation) Optional.of(e) | |
| else Optional.empty() | |
| } | |
| boolean visit(MethodDeclaration node) { | |
| if (node.modifiers().size() < 1) return | |
| if (repository.isAlreadyImported("org.springframework.web.bind.annotation.RequestMapping") == false) { | |
| return false | |
| } | |
| node.modifiers().eachWithIndex { m, i -> | |
| if(m instanceof NormalAnnotation && m.typeName.fullyQualifiedName == "RequestMapping") { | |
| MemberValuePairRepository pairRepository = new MemberValuePairRepository(m.values()) | |
| pairRepository.findMember("method") | |
| .map {it.value.toString() } | |
| .map {identifier -> | |
| if(repository.isAlreadyImported("org.springframework.web.bind.annotation.RequestMethod")){ | |
| switch(identifier){ | |
| case "RequestMethod.GET": return "GetMapping" | |
| case "RequestMethod.POST": return "PostMapping" | |
| case "RequestMethod.PUT": return "PutMapping" | |
| case "RequestMethod.DELETE": return "DeleteMapping" | |
| case "RequestMethod.PATCH": return "PatchMapping" | |
| } | |
| } | |
| switch(identifier) { | |
| case ["GET", "POST", "PUT", "DELETE", "PATCH"]: | |
| if(repository.isAlreadyStaticImported( | |
| "org.springframework.web.bind.annotation.RequestMethod.$identifier")){ | |
| def l=identifier.toLowerCase() | |
| return l[0].toUpperCase() + l[1..l.length] + "Mapping" | |
| } | |
| } | |
| } | |
| .map { annotationName -> | |
| repository.add("org.springframework.web.bind.annotation.$annotationName") | |
| List<MemberValuePair> pairs = pairRepository.findExcludeMember("method") | |
| Annotation annotation = { | |
| switch(pairs) { | |
| case { pairs.isEmpty() } : return ast.newMarkerAnnotation() | |
| case { pairs.size == 1 && (pairs[0].name.identifier == "path" || pairs[0].name.identifier == "value" )} : | |
| MemberValuePair pair = pairs[0] | |
| SingleMemberAnnotation memberAnnotation = | |
| ast.newSingleMemberAnnotation() | |
| ASTRewrite rewriter = ASTRewrite.create(ast); | |
| memberAnnotation.value = ASTNode.copySubtree( | |
| rewriter.createMoveTarget(pair.value).getAST(), pair.value | |
| ) | |
| return memberAnnotation | |
| default: | |
| NormalAnnotation n = ast.newNormalAnnotation() | |
| pairs.stream().map { ASTNode.copySubtree(ast.newMemberValuePair().ast, it) } | |
| .forEach(n.values().&add) | |
| return n | |
| } | |
| }() | |
| annotation.typeName = ast.newSimpleName(annotationName) | |
| annotation | |
| } | |
| .ifPresent { node.modifiers()[i]= it } | |
| } | |
| } | |
| return false | |
| } | |
| } | |
| def dir = new File(args[0]) | |
| def migrate = new Migrator().&migrate | |
| if(dir.isDirectory()){ | |
| dir.eachFileRecurse (FileType.FILES) { | |
| if (it.name.endsWith(".java")){ | |
| println(it.name) | |
| it.text = migrate(it.text) | |
| } | |
| } | |
| } else { | |
| assert dir.name.endsWith(".java") | |
| println(dir.name) | |
| dir.text = migrate(dir.text) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment