Skip to content

Instantly share code, notes, and snippets.

@wreulicke
Last active August 2, 2017 13:34
Show Gist options
  • Select an option

  • Save wreulicke/8c2b4baaf92fef332f05d1eb011b1038 to your computer and use it in GitHub Desktop.

Select an option

Save wreulicke/8c2b4baaf92fef332f05d1eb011b1038 to your computer and use it in GitHub Desktop.
migration script
@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