Skip to content

Commit

Permalink
Fix generics weirdness that failed on Java 9
Browse files Browse the repository at this point in the history
  • Loading branch information
matozoid committed Nov 5, 2017
1 parent 2740e3b commit bb989d9
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 53 deletions.
@@ -1,15 +1,19 @@
package com.github.javaparser.generator; package com.github.javaparser.generator;


import com.github.javaparser.ast.Node; import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.StringLiteralExpr; import com.github.javaparser.ast.expr.StringLiteralExpr;
import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations; import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;
import com.github.javaparser.utils.SourceRoot; import com.github.javaparser.utils.SourceRoot;


import javax.annotation.Generated; import javax.annotation.Generated;
import java.util.List;


import static com.github.javaparser.ast.NodeList.toNodeList; import static com.github.javaparser.ast.NodeList.toNodeList;
import static com.github.javaparser.utils.CodeGenerationUtils.f;


/** /**
* A general pattern that the generators in this module will follow. * A general pattern that the generators in this module will follow.
Expand All @@ -23,15 +27,19 @@ protected Generator(SourceRoot sourceRoot) {


public abstract void generate() throws Exception; public abstract void generate() throws Exception;


protected <T extends Node & NodeWithAnnotations<? extends T>> void annotateGenerated(T node) { protected <T extends Node & NodeWithAnnotations<?>> void annotateGenerated(T node) {
annotate(node, Generated.class, new StringLiteralExpr(getClass().getName())); annotate(node, Generated.class, new StringLiteralExpr(getClass().getName()));
} }


protected <T extends Node & NodeWithAnnotations<? extends T>> void annotateSuppressWarnings(T node) { protected <T extends Node & NodeWithAnnotations<?>> void annotateSuppressWarnings(T node) {
annotate(node, SuppressWarnings.class, new StringLiteralExpr("unchecked")); annotate(node, SuppressWarnings.class, new StringLiteralExpr("unchecked"));
} }


private <T extends Node & NodeWithAnnotations<? extends T>> void annotate(T node, Class<?> annotation, Expression content) { protected void annotateOverridden(MethodDeclaration method) {
annotate(method, Override.class, null);
}

private <T extends Node & NodeWithAnnotations<?>> void annotate(T node, Class<?> annotation, Expression content) {
node.setAnnotations( node.setAnnotations(
node.getAnnotations().stream() node.getAnnotations().stream()
.filter(a -> !a.getNameAsString().equals(annotation.getSimpleName())) .filter(a -> !a.getNameAsString().equals(annotation.getSimpleName()))
Expand All @@ -45,8 +53,52 @@ private <T extends Node & NodeWithAnnotations<? extends T>> void annotate(T node
node.tryAddImportToParentCompilationUnit(annotation); node.tryAddImportToParentCompilationUnit(annotation);
} }


protected void annotateOverridden(MethodDeclaration method) { /**
annotate(method, Override.class, null); * Utility method that looks for a method or constructor with an identical signature as "callable" and replaces it
* with callable. If not found, adds callable. When the new callable has no javadoc, any old javadoc will be kept.
*/
protected void addOrReplaceWhenSameSignature(ClassOrInterfaceDeclaration containingClassOrInterface, CallableDeclaration<?> callable) {
addMethod(containingClassOrInterface, callable, () -> containingClassOrInterface.addMember(callable));
}

/**
* Utility method that looks for a method or constructor with an identical signature as "callable" and replaces it
* with callable. If not found, fails. When the new callable has no javadoc, any old javadoc will be kept. The
* method or constructor is annotated with the generator class.
*/
protected void replaceWhenSameSignature(ClassOrInterfaceDeclaration containingClassOrInterface, CallableDeclaration<?> callable) {
addMethod(containingClassOrInterface, callable,
() -> {
throw new AssertionError(f("Wanted to regenerate a method with signature %s in %s, but it wasn't there.", callable.getSignature(), containingClassOrInterface.getNameAsString()));
});
}

private void addMethod(
ClassOrInterfaceDeclaration containingClassOrInterface,
CallableDeclaration<?> callable,
Runnable onNoExistingMethod) {
List<CallableDeclaration<?>> existingCallables = containingClassOrInterface.getCallablesWithSignature(callable.getSignature());
if (existingCallables.isEmpty()) {
onNoExistingMethod.run();
return;
}
if (existingCallables.size() > 1) {
throw new AssertionError(f("Wanted to regenerate a method with signature %s in %s, but found more than one.", callable.getSignature(), containingClassOrInterface.getNameAsString()));
}
final CallableDeclaration<?> existingCallable = existingCallables.get(0);
callable.setJavadocComment(callable.getJavadocComment().orElse(existingCallable.getJavadocComment().orElse(null)));
annotateGenerated(callable);
containingClassOrInterface.getMembers().replace(existingCallable, callable);
}

/**
* Removes all methods from containingClassOrInterface that have the same signature as callable. This is not used by
* any code, but it is useful when changing a generator and you need to get rid of a set of outdated methods.
*/
protected void removeMethodWithSameSignature(ClassOrInterfaceDeclaration containingClassOrInterface, CallableDeclaration<?> callable) {
for (CallableDeclaration<?> existingCallable : containingClassOrInterface.getCallablesWithSignature(callable.getSignature())) {
containingClassOrInterface.remove(existingCallable);
}
} }


} }
Expand Up @@ -43,52 +43,4 @@ protected void after() throws Exception {
} }


protected abstract void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) throws Exception; protected abstract void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) throws Exception;

/**
* Utility method that looks for a method or constructor with an identical signature as "callable" and replaces it
* with callable. If not found, adds callable. When the new callable has no javadoc, any old javadoc will be kept.
*/
protected void addOrReplaceWhenSameSignature(ClassOrInterfaceDeclaration containingClassOrInterface, CallableDeclaration<?> callable) {
addMethod(containingClassOrInterface, callable, () -> containingClassOrInterface.addMember(callable));
}

/**
* Utility method that looks for a method or constructor with an identical signature as "callable" and replaces it
* with callable. If not found, fails. When the new callable has no javadoc, any old javadoc will be kept. The
* method or constructor is annotated with the generator class.
*/
protected void replaceWhenSameSignature(ClassOrInterfaceDeclaration containingClassOrInterface, CallableDeclaration<?> callable) {
addMethod(containingClassOrInterface, callable,
() -> {
throw new AssertionError(f("Wanted to regenerate a method with signature %s in %s, but it wasn't there.", callable.getSignature(), containingClassOrInterface.getNameAsString()));
});
}

private void addMethod(
ClassOrInterfaceDeclaration containingClassOrInterface,
CallableDeclaration<?> callable,
Runnable onNoExistingMethod) {
List<CallableDeclaration<?>> existingCallables = containingClassOrInterface.getCallablesWithSignature(callable.getSignature());
if (existingCallables.isEmpty()) {
onNoExistingMethod.run();
return;
}
if (existingCallables.size() > 1) {
throw new AssertionError(f("Wanted to regenerate a method with signature %s in %s, but found more than one.", callable.getSignature(), containingClassOrInterface.getNameAsString()));
}
final CallableDeclaration<?> existingCallable = existingCallables.get(0);
callable.setJavadocComment(callable.getJavadocComment().orElse(existingCallable.getJavadocComment().orElse(null)));
annotateGenerated(callable);
containingClassOrInterface.getMembers().replace(existingCallable, callable);
}

/**
* Removes all methods from containingClassOrInterface that have the same signature as callable. This is not used by
* any code, but it is useful when changing a generator and you need to get rid of a set of outdated methods.
*/
protected void removeMethodWithSameSignature(ClassOrInterfaceDeclaration containingClassOrInterface, CallableDeclaration<?> callable) {
for (CallableDeclaration<?> existingCallable : containingClassOrInterface.getCallablesWithSignature(callable.getSignature())) {
containingClassOrInterface.remove(existingCallable);
}
}
} }

0 comments on commit bb989d9

Please sign in to comment.