Skip to content

Commit

Permalink
improve how javassist handle generics
Browse files Browse the repository at this point in the history
  • Loading branch information
ftomassetti committed Oct 26, 2016
1 parent 92536dd commit 8ddfe46
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 76 deletions.
Expand Up @@ -278,26 +278,42 @@ public boolean isClass() {
} }


@Override @Override
public ReferenceTypeImpl getSuperClass() { public ReferenceType getSuperClass() {
try { try {
if (ctClass.getSuperclass() == null) { if (ctClass.getSuperclass() == null) {
return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver); return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
} }
return new ReferenceTypeImpl(new JavassistClassDeclaration(ctClass.getSuperclass(), typeSolver).asClass(), typeSolver); if (ctClass.getGenericSignature() == null) {
return new ReferenceTypeImpl(new JavassistClassDeclaration(ctClass.getSuperclass(), typeSolver), typeSolver);
}

SignatureAttribute.ClassSignature classSignature = SignatureAttribute.toClassSignature(ctClass.getGenericSignature());
return JavassistUtils.signatureTypeToType(classSignature.getSuperClass(), typeSolver, this).asReferenceType();
} catch (NotFoundException e) { } catch (NotFoundException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (BadBytecode e) {
throw new RuntimeException(e);
} }
} }


@Override @Override
public List<ReferenceType> getInterfaces() { public List<ReferenceType> getInterfaces() {
try { try {
return Arrays.stream(ctClass.getInterfaces()) if (ctClass.getGenericSignature() == null) {
.map(i -> new JavassistInterfaceDeclaration(i, typeSolver)) return Arrays.stream(ctClass.getInterfaces())
.map(i -> new ReferenceTypeImpl(i, typeSolver)) .map(i -> new JavassistInterfaceDeclaration(i, typeSolver))
.collect(Collectors.toList()); .map(i -> new ReferenceTypeImpl(i, typeSolver))
.collect(Collectors.toList());
} else {
SignatureAttribute.ClassSignature classSignature = SignatureAttribute.toClassSignature(ctClass.getGenericSignature());
return Arrays.stream(classSignature.getInterfaces())
.map(i -> JavassistUtils.signatureTypeToType(i, typeSolver, this).asReferenceType())
.collect(Collectors.toList());
}
} catch (NotFoundException e) { } catch (NotFoundException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (BadBytecode e) {
throw new RuntimeException(e);
} }
} }


Expand Down Expand Up @@ -335,4 +351,17 @@ public AccessLevel accessLevel() {
public List<ConstructorDeclaration> getConstructors() { public List<ConstructorDeclaration> getConstructors() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

@Override
public Optional<TypeDeclaration> containerType() {
try {
if (ctClass.getDeclaringClass() == null) {
return Optional.empty();
} else {
throw new UnsupportedOperationException();
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
} }
Expand Up @@ -19,12 +19,9 @@
import com.github.javaparser.ast.Node; import com.github.javaparser.ast.Node;
import com.github.javaparser.symbolsolver.core.resolution.Context; import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.model.declarations.*; import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage; import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type; import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.model.typesystem.TypeVariable;
import com.github.javaparser.symbolsolver.model.typesystem.Wildcard;
import javassist.CtMethod; import javassist.CtMethod;
import javassist.NotFoundException; import javassist.NotFoundException;
import javassist.bytecode.BadBytecode; import javassist.bytecode.BadBytecode;
Expand All @@ -34,7 +31,6 @@
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;


public class JavassistMethodDeclaration implements MethodDeclaration { public class JavassistMethodDeclaration implements MethodDeclaration {
Expand Down Expand Up @@ -116,7 +112,7 @@ public ParameterDeclaration getParam(int i) {
if (ctMethod.getGenericSignature() != null) { if (ctMethod.getGenericSignature() != null) {
SignatureAttribute.MethodSignature methodSignature = SignatureAttribute.toMethodSignature(ctMethod.getGenericSignature()); SignatureAttribute.MethodSignature methodSignature = SignatureAttribute.toMethodSignature(ctMethod.getGenericSignature());
SignatureAttribute.Type signatureType = methodSignature.getParameterTypes()[i]; SignatureAttribute.Type signatureType = methodSignature.getParameterTypes()[i];
return new JavassistParameterDeclaration(signatureTypeToType(signatureType), typeSolver, variadic); return new JavassistParameterDeclaration(JavassistUtils.signatureTypeToType(signatureType, typeSolver, this), typeSolver, variadic);
} else { } else {
return new JavassistParameterDeclaration(ctMethod.getParameterTypes()[0], typeSolver, variadic); return new JavassistParameterDeclaration(ctMethod.getParameterTypes()[0], typeSolver, variadic);
} }
Expand All @@ -127,48 +123,6 @@ public ParameterDeclaration getParam(int i) {
} }
} }


private Type signatureTypeToType(SignatureAttribute.Type signatureType){
if (signatureType instanceof SignatureAttribute.ClassType) {
SignatureAttribute.ClassType classType = (SignatureAttribute.ClassType)signatureType;
List<Type> typeParameters = Arrays.stream(classType.getTypeArguments()).map(ta -> typeArgumentToType(ta)).collect(Collectors.toList());
TypeDeclaration typeDeclaration = typeSolver.solveType(classType.getName());
return new ReferenceTypeImpl(typeDeclaration, typeParameters, typeSolver);
} else {
throw new RuntimeException(signatureType.getClass().getCanonicalName());
}
}

private Type objectTypeArgumentToType(SignatureAttribute.ObjectType typeArgument){
String typeName = typeArgument.jvmTypeName();
Optional<Type> type = getGenericParameterByName(typeName);
if (type.isPresent()) {
return type.get();
} else {
throw new UnsupportedOperationException(typeName);
}
}

private Optional<Type> getGenericParameterByName(String typeName) {
Optional<TypeParameterDeclaration> tp = findTypeParameter(typeName);
return tp.map(it -> new TypeVariable(it));
}

private Type typeArgumentToType(SignatureAttribute.TypeArgument typeArgument){
if (typeArgument.isWildcard()) {
if (typeArgument.getType() == null) {
return Wildcard.UNBOUNDED;
} else if (typeArgument.getKind() == '+'){
return Wildcard.extendsBound(objectTypeArgumentToType(typeArgument.getType()));
} else if (typeArgument.getKind() == '-'){
return Wildcard.superBound(objectTypeArgumentToType(typeArgument.getType()));
} else {
throw new UnsupportedOperationException();
}
} else {
throw new UnsupportedOperationException();
}
}

public MethodUsage getUsage(Node node) { public MethodUsage getUsage(Node node) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
Expand Down
Expand Up @@ -18,20 +18,24 @@


import com.github.javaparser.symbolsolver.core.resolution.Context; import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javassistmodel.contexts.JavassistMethodContext; import com.github.javaparser.symbolsolver.javassistmodel.contexts.JavassistMethodContext;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParametrizable;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage; import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type; import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.model.typesystem.TypeVariable;
import com.github.javaparser.symbolsolver.model.typesystem.Wildcard;
import com.github.javaparser.symbolsolver.resolution.SymbolSolver; import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
import javassist.CtClass; import javassist.CtClass;
import javassist.CtMethod; import javassist.CtMethod;
import javassist.NotFoundException; import javassist.NotFoundException;
import javassist.bytecode.BadBytecode; import javassist.bytecode.BadBytecode;
import javassist.bytecode.SignatureAttribute; import javassist.bytecode.SignatureAttribute;


import java.util.ArrayList; import java.util.*;
import java.util.Collections; import java.util.stream.Collectors;
import java.util.List;
import java.util.Optional;


/** /**
* @author Federico Tomassetti * @author Federico Tomassetti
Expand Down Expand Up @@ -110,4 +114,46 @@ private static List<Type> parseTypeParameters(String signature, TypeSolver typeS
return Collections.emptyList(); return Collections.emptyList();
} }
} }

static Type signatureTypeToType(SignatureAttribute.Type signatureType, TypeSolver typeSolver, TypeParametrizable typeParametrizable){
if (signatureType instanceof SignatureAttribute.ClassType) {
SignatureAttribute.ClassType classType = (SignatureAttribute.ClassType)signatureType;
List<Type> typeParameters = classType.getTypeArguments() == null ? Collections.emptyList() : Arrays.stream(classType.getTypeArguments()).map(ta -> typeArgumentToType(ta, typeSolver, typeParametrizable)).collect(Collectors.toList());
TypeDeclaration typeDeclaration = typeSolver.solveType(classType.getName());
return new ReferenceTypeImpl(typeDeclaration, typeParameters, typeSolver);
} else {
throw new RuntimeException(signatureType.getClass().getCanonicalName());
}
}

private static Type objectTypeArgumentToType(SignatureAttribute.ObjectType typeArgument, TypeSolver typeSolver, TypeParametrizable typeParametrizable){
String typeName = typeArgument.jvmTypeName();
Optional<Type> type = getGenericParameterByName(typeName, typeParametrizable);
if (type.isPresent()) {
return type.get();
} else {
return new ReferenceTypeImpl(typeSolver.solveType(typeName), typeSolver);
}
}

private static Optional<Type> getGenericParameterByName(String typeName, TypeParametrizable typeParametrizable) {
Optional<TypeParameterDeclaration> tp = typeParametrizable.findTypeParameter(typeName);
return tp.map(it -> new TypeVariable(it));
}

private static Type typeArgumentToType(SignatureAttribute.TypeArgument typeArgument, TypeSolver typeSolver, TypeParametrizable typeParametrizable){
if (typeArgument.isWildcard()) {
if (typeArgument.getType() == null) {
return Wildcard.UNBOUNDED;
} else if (typeArgument.getKind() == '+') {
return Wildcard.extendsBound(objectTypeArgumentToType(typeArgument.getType(), typeSolver, typeParametrizable));
} else if (typeArgument.getKind() == '-') {
return Wildcard.superBound(objectTypeArgumentToType(typeArgument.getType(), typeSolver, typeParametrizable));
} else {
throw new UnsupportedOperationException();
}
} else {
return objectTypeArgumentToType(typeArgument.getType(), typeSolver, typeParametrizable);
}
}
} }
Expand Up @@ -120,6 +120,19 @@ public void testGetSuperclass() {
assertEquals("com.github.javaparser.ast.Node", compilationUnit.getSuperClass().getQualifiedName()); assertEquals("com.github.javaparser.ast.Node", compilationUnit.getSuperClass().getQualifiedName());
} }


@Test
public void testGetSuperclassWithoutTypeParameters() {
JavassistClassDeclaration compilationUnit = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.CompilationUnit");
assertEquals("com.github.javaparser.ast.Node", compilationUnit.getSuperClass().getQualifiedName());
}

@Test
public void testGetSuperclassWithTypeParameters() {
JavassistClassDeclaration compilationUnit = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ConstructorDeclaration");
assertEquals("com.github.javaparser.ast.body.BodyDeclaration", compilationUnit.getSuperClass().getQualifiedName());
assertEquals("com.github.javaparser.ast.body.ConstructorDeclaration", compilationUnit.getSuperClass().typeParametersMap().getValueBySignature("com.github.javaparser.ast.body.BodyDeclaration.T").get().asReferenceType().getQualifiedName());
}

@Test @Test
public void testGetAllSuperclasses() { public void testGetAllSuperclasses() {
JavassistClassDeclaration cu = (JavassistClassDeclaration) typeSolver.solveType("com.github.javaparser.ast.CompilationUnit"); JavassistClassDeclaration cu = (JavassistClassDeclaration) typeSolver.solveType("com.github.javaparser.ast.CompilationUnit");
Expand Down Expand Up @@ -150,19 +163,6 @@ public void testGetAllInterfaces() {
assertEquals(ImmutableSet.of("com.github.javaparser.ast.NamedNode", "com.github.javaparser.ast.body.AnnotableNode", "com.github.javaparser.ast.DocumentableNode"), coid.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); assertEquals(ImmutableSet.of("com.github.javaparser.ast.NamedNode", "com.github.javaparser.ast.body.AnnotableNode", "com.github.javaparser.ast.DocumentableNode"), coid.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet()));
} }


@Test
public void testGetSuperclassWithoutTypeParameters() {
JavassistClassDeclaration compilationUnit = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.CompilationUnit");
assertEquals("com.github.javaparser.ast.Node", compilationUnit.getSuperClass().getQualifiedName());
}

@Test
public void testGetSuperclassWithTypeParameters() {
JavassistClassDeclaration compilationUnit = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ConstructorDeclaration");
assertEquals("com.github.javaparser.ast.body.BodyDeclaration", compilationUnit.getSuperClass().getQualifiedName());
assertEquals("com.github.javaparser.ast.body.ConstructorDeclaration", compilationUnit.getSuperClass().typeParametersMap().getValueBySignature("com.github.javaparser.ast.body.BodyDeclaration.T").get().asReferenceType().getQualifiedName());
}

@Test @Test
public void testGetAllSuperclassesWithoutTypeParameters() { public void testGetAllSuperclassesWithoutTypeParameters() {
JavassistClassDeclaration cu = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.CompilationUnit"); JavassistClassDeclaration cu = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.CompilationUnit");
Expand Down Expand Up @@ -196,7 +196,7 @@ public void testGetInterfacesWithoutParameters() {
assertEquals(ImmutableSet.of(), compilationUnit.getInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); assertEquals(ImmutableSet.of(), compilationUnit.getInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet()));


JavassistClassDeclaration coid = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ClassOrInterfaceDeclaration"); JavassistClassDeclaration coid = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ClassOrInterfaceDeclaration");
assertEquals(ImmutableSet.of("com.github.javaparser.ast.DocumentableNode"), coid.getInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); assertEquals(ImmutableSet.of("com.github.javaparser.ast.nodeTypes.NodeWithExtends", "com.github.javaparser.ast.nodeTypes.NodeWithImplements"), coid.getInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet()));
} }


@Test @Test
Expand Down Expand Up @@ -240,7 +240,14 @@ public void testGetAllInterfacesWithoutParameters() {
assertEquals(ImmutableSet.of("java.lang.Cloneable"), compilationUnit.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); assertEquals(ImmutableSet.of("java.lang.Cloneable"), compilationUnit.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet()));


JavassistClassDeclaration coid = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ClassOrInterfaceDeclaration"); JavassistClassDeclaration coid = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ClassOrInterfaceDeclaration");
assertEquals(ImmutableSet.of("java.lang.Cloneable", "com.github.javaparser.ast.NamedNode", "com.github.javaparser.ast.body.AnnotableNode", "com.github.javaparser.ast.DocumentableNode"), coid.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); assertEquals(ImmutableSet.of("com.github.javaparser.ast.nodeTypes.NodeWithExtends",
"com.github.javaparser.ast.nodeTypes.NodeWithAnnotations",
"java.lang.Cloneable",
"com.github.javaparser.ast.nodeTypes.NodeWithImplements",
"com.github.javaparser.ast.nodeTypes.NodeWithName",
"com.github.javaparser.ast.nodeTypes.NodeWithModifiers",
"com.github.javaparser.ast.nodeTypes.NodeWithJavaDoc",
"com.github.javaparser.ast.nodeTypes.NodeWithMembers"), coid.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet()));
} }


@Test @Test
Expand Down Expand Up @@ -326,7 +333,7 @@ public void testGetAncestorsWithTypeParameters() {


@Test @Test
public void testGetAllAncestorsWithoutTypeParameters() { public void testGetAllAncestorsWithoutTypeParameters() {
JavassistClassDeclaration cu = (JavassistClassDeclaration) typeSolver.solveType("com.github.javaparser.ast.CompilationUnit"); JavassistClassDeclaration cu = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.CompilationUnit");
assertEquals(ImmutableSet.of("java.lang.Cloneable", "com.github.javaparser.ast.Node", "java.lang.Object"), cu.getAllAncestors().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); assertEquals(ImmutableSet.of("java.lang.Cloneable", "com.github.javaparser.ast.Node", "java.lang.Object"), cu.getAllAncestors().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet()));
} }


Expand Down Expand Up @@ -380,5 +387,6 @@ public void testGetAllAncestorsWithTypeParameters() {
ancestor = constructorDeclaration.getAllAncestors().get(11); ancestor = constructorDeclaration.getAllAncestors().get(11);
assertEquals("com.github.javaparser.ast.nodeTypes.NodeWithBlockStmt", ancestor.getQualifiedName()); assertEquals("com.github.javaparser.ast.nodeTypes.NodeWithBlockStmt", ancestor.getQualifiedName());
assertEquals("com.github.javaparser.ast.body.ConstructorDeclaration", ancestor.typeParametersMap().getValueBySignature("com.github.javaparser.ast.nodeTypes.NodeWithBlockStmt.T").get().asReferenceType().getQualifiedName()); assertEquals("com.github.javaparser.ast.body.ConstructorDeclaration", ancestor.typeParametersMap().getValueBySignature("com.github.javaparser.ast.nodeTypes.NodeWithBlockStmt.T").get().asReferenceType().getQualifiedName());
} }

} }
Expand Up @@ -50,7 +50,7 @@ default Set<TypeDeclaration> internalTypes() {
* @return * @return
*/ */
default Optional<TypeDeclaration> containerType() { default Optional<TypeDeclaration> containerType() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException("containerType is not supported for " + this.getClass().getCanonicalName());
} }


/// ///
Expand Down

0 comments on commit 8ddfe46

Please sign in to comment.