Skip to content

Commit

Permalink
Refactored type variable erasure.
Browse files Browse the repository at this point in the history
  • Loading branch information
raphw committed Jan 18, 2016
1 parent 0b83a65 commit 6732540
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 163 deletions.
9 changes: 8 additions & 1 deletion byte-buddy-dep/pom.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>


<parent> <parent>
Expand Down Expand Up @@ -54,6 +55,12 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>


</project> </project>
Expand Up @@ -61,7 +61,7 @@ interface Visitor<T> {
* @param methodDescription The method onto which this visitor is applied. * @param methodDescription The method onto which this visitor is applied.
* @return The visitor's return value. * @return The visitor's return value.
*/ */
T onMethod(MethodDescription methodDescription); T onMethod(MethodDescription.InDefinedShape methodDescription);


/** /**
* A none-operational implementation of a type variable visitor that simply returns the visited source. * A none-operational implementation of a type variable visitor that simply returns the visited source.
Expand All @@ -79,7 +79,7 @@ public TypeVariableSource onType(TypeDescription typeDescription) {
} }


@Override @Override
public TypeVariableSource onMethod(MethodDescription methodDescription) { public TypeVariableSource onMethod(MethodDescription.InDefinedShape methodDescription) {
return methodDescription; return methodDescription;
} }


Expand Down
Expand Up @@ -568,7 +568,7 @@ public TypeDescription.Generic findVariable(String symbol) {


@Override @Override
public <T> T accept(TypeVariableSource.Visitor<T> visitor) { public <T> T accept(TypeVariableSource.Visitor<T> visitor) {
return visitor.onMethod(this); return visitor.onMethod(this.asDefined()); // TODO!
} }


@Override @Override
Expand Down Expand Up @@ -1154,22 +1154,22 @@ public TypeSubstituting(TypeDescription.Generic declaringType,


@Override @Override
public TypeList.Generic getTypeVariables() { public TypeList.Generic getTypeVariables() {
return new TypeList.Generic.ForDetachedTypes(methodDescription.getTypeVariables(), new VariableRetainingDelegator()); return new TypeList.Generic.ForDetachedTypes(methodDescription.getTypeVariables(), visitor);
} }


@Override @Override
public TypeDescription.Generic getReturnType() { public TypeDescription.Generic getReturnType() {
return methodDescription.getReturnType().accept(new VariableRetainingDelegator()); return methodDescription.getReturnType().accept(visitor);
} }


@Override @Override
public ParameterList<ParameterDescription.InGenericShape> getParameters() { public ParameterList<ParameterDescription.InGenericShape> getParameters() {
return new ParameterList.TypeSubstituting(this, methodDescription.getParameters(), new VariableRetainingDelegator()); return new ParameterList.TypeSubstituting(this, methodDescription.getParameters(), visitor);
} }


@Override @Override
public TypeList.Generic getExceptionTypes() { public TypeList.Generic getExceptionTypes() {
return new TypeList.Generic.ForDetachedTypes(methodDescription.getExceptionTypes(), new VariableRetainingDelegator()); return new TypeList.Generic.ForDetachedTypes(methodDescription.getExceptionTypes(), visitor);
} }


@Override @Override
Expand Down Expand Up @@ -1201,121 +1201,6 @@ public String getInternalName() {
public InDefinedShape asDefined() { public InDefinedShape asDefined() {
return methodDescription.asDefined(); return methodDescription.asDefined();
} }

/**
* A visitor that only escalates to the actual visitor if a non-generic type is discovered or if a type variable
* that is not declared by the represented method is discovered. This way, a method's type variables are never bound
* by the supplied visitor as non-generic types never reference a method's type variables and since a type variable
* that is not declared by the represented method can never reference a type variable of the represented method.
*/
protected class VariableRetainingDelegator extends TypeDescription.Generic.Visitor.Substitutor {

@Override
public TypeDescription.Generic onParameterizedType(TypeDescription.Generic parameterizedType) {
List<TypeDescription.Generic> parameters = new ArrayList<TypeDescription.Generic>(parameterizedType.getTypeArguments().size());
for (TypeDescription.Generic parameter : parameterizedType.getTypeArguments()) {
if (parameter.getSort().isTypeVariable() && !methodDescription.getTypeVariables().contains(parameter)) {
return visitor.onParameterizedType(parameterizedType);
} else if (parameter.getSort().isWildcard()) {
TypeList.Generic bounds = parameter.getLowerBounds();
bounds = bounds.isEmpty() ? parameter.getUpperBounds() : bounds;
if (bounds.getOnly().getSort().isTypeVariable() && !methodDescription.getTypeVariables().contains(parameter)) {
return visitor.onParameterizedType(parameterizedType);
}
}
parameters.add(parameter.accept(this));
}
TypeDescription.Generic ownerType = parameterizedType.getOwnerType();
return new TypeDescription.Generic.OfParameterizedType.Latent(parameterizedType.asErasure(),
ownerType == null
? TypeDescription.Generic.UNDEFINED
: ownerType.accept(this),
parameters,
parameterizedType.getDeclaredAnnotations());
}

@Override
public TypeDescription.Generic onNonGenericType(TypeDescription.Generic typeDescription) {
return visitor.onNonGenericType(typeDescription);
}

@Override
protected TypeDescription.Generic onSimpleType(TypeDescription.Generic typeDescription) {
throw new UnsupportedOperationException();
}

@Override
public TypeDescription.Generic onTypeVariable(TypeDescription.Generic typeVariable) {
return methodDescription.getTypeVariables().contains(typeVariable)
? new RetainedVariable(typeVariable)
: visitor.onTypeVariable(typeVariable);
}

@Override
public int hashCode() {
return TypeSubstituting.this.hashCode();
}

@Override
public boolean equals(Object other) {
return other != null && other.getClass() == this.getClass()
&& TypeSubstituting.this.equals(((VariableRetainingDelegator) other).getOuter());
}

/**
* Returns the outer instance.
*
* @return The outer instance.
*/
private Object getOuter() {
return TypeSubstituting.this;
}

@Override
public String toString() {
return "MethodDescription.TypeSubstituting.VariableRetainingDelegator{methodDescription=" + TypeSubstituting.this + '}';
}

/**
* A retained type variable that is declared by the method.
*/
protected class RetainedVariable extends TypeDescription.Generic.OfTypeVariable {

/**
* The type variable this retained variable represents.
*/
private final TypeDescription.Generic typeVariable;

/**
* Creates a new retained type variable.
*
* @param typeVariable The type variable this retained variable represents.
*/
protected RetainedVariable(TypeDescription.Generic typeVariable) {
this.typeVariable = typeVariable;
}

@Override
public TypeList.Generic getUpperBounds() {
return new TypeList.Generic.ForDetachedTypes(typeVariable.getUpperBounds(), VariableRetainingDelegator.this);
}

@Override
public TypeVariableSource getVariableSource() {
return TypeSubstituting.this;
}

@Override
public String getSymbol() {
return typeVariable.getSymbol();
}

@Override
public AnnotationList getDeclaredAnnotations() {
return typeVariable.getDeclaredAnnotations();
}
}
}
} }


/** /**
Expand Down
Expand Up @@ -688,12 +688,12 @@ public Generic onParameterizedType(Generic parameterizedType) {


@Override @Override
public Generic onTypeVariable(Generic typeVariable) { public Generic onTypeVariable(Generic typeVariable) {
return new OfNonGenericType.Latent(typeVariable.asErasure(), typeVariable.getDeclaredAnnotations()); return typeVariable.getVariableSource().accept(new TypeVariableReviser(typeVariable));
} }


@Override @Override
public Generic onNonGenericType(Generic typeDescription) { public Generic onNonGenericType(Generic typeDescription) {
return new OfNonGenericType.Latent(typeDescription.asErasure(), typeDescription.getDeclaredAnnotations()); return new OfNonGenericType.Latent(typeDescription.asErasure(), typeDescription.getDeclaredAnnotations()); // TODO: Retain old value?
} }


@Override @Override
Expand Down Expand Up @@ -746,6 +746,54 @@ public String toString() {
return "TypeDescription.Generic.Visitor.TypeVariableErasing.PartialErasureReviser." + name(); return "TypeDescription.Generic.Visitor.TypeVariableErasing.PartialErasureReviser." + name();
} }
} }

protected static class TypeVariableReviser implements TypeVariableSource.Visitor<Generic> {

private final Generic typeVariable;

protected TypeVariableReviser(Generic typeVariable) {
this.typeVariable = typeVariable;
}

@Override
public Generic onType(TypeDescription typeDescription) {
return new OfNonGenericType.Latent(typeVariable.asErasure(), typeVariable.getDeclaredAnnotations());
}

@Override
public Generic onMethod(MethodDescription.InDefinedShape methodDescription) {
return new RetainedTypeVariable(typeVariable);
}
}

protected static class RetainedTypeVariable extends OfTypeVariable {

private final Generic typeVariable;

protected RetainedTypeVariable(Generic typeVariable) {
this.typeVariable = typeVariable;
}

@Override
public TypeList.Generic getUpperBounds() {
return typeVariable.getUpperBounds().accept(TypeVariableErasing.INSTANCE);
}

@Override
public TypeVariableSource getVariableSource() {
return typeVariable.getVariableSource();
}

@Override
public String getSymbol() {
return typeVariable.getSymbol();
}

@Override
public AnnotationList getDeclaredAnnotations() {
return typeVariable.getDeclaredAnnotations();
}
}
} }


/** /**
Expand Down Expand Up @@ -2051,12 +2099,7 @@ public static Visitor<Generic> bind(Generic typeDescription) {


@Override @Override
public Generic onTypeVariable(Generic typeVariable) { public Generic onTypeVariable(Generic typeVariable) {
Generic substitution = bindings.get(typeVariable); return typeVariable.getVariableSource().accept(new TypeVariableSubstitutor(typeVariable));
if (substitution == null) {
throw new IllegalStateException("Unknown type variable: " + typeVariable);
} else {
return substitution;
}
} }


@Override @Override
Expand Down Expand Up @@ -2088,6 +2131,59 @@ public String toString() {
"bindings=" + bindings + "bindings=" + bindings +
'}'; '}';
} }

protected class TypeVariableSubstitutor implements TypeVariableSource.Visitor<Generic> {

private final Generic typeVariable;

protected TypeVariableSubstitutor(Generic typeVariable) {
this.typeVariable = typeVariable;
}

@Override
public Generic onType(TypeDescription typeDescription) {
Generic substitution = bindings.get(typeVariable);
if (substitution == null) {
throw new IllegalStateException("Unknown type variable: " + typeVariable);
} else {
return substitution;
}
}

@Override
public Generic onMethod(MethodDescription.InDefinedShape methodDescription) {
return new RetainedMethodTypeVariable(typeVariable);
}
}

protected class RetainedMethodTypeVariable extends OfTypeVariable {

private final Generic typeVariable;

protected RetainedMethodTypeVariable(Generic typeVariable) {
this.typeVariable = typeVariable;
}

@Override
public TypeList.Generic getUpperBounds() {
return typeVariable.getUpperBounds().accept(ForTypeVariableBinding.this);
}

@Override
public TypeVariableSource getVariableSource() {
return typeVariable.getVariableSource();
}

@Override
public String getSymbol() {
return typeVariable.getSymbol();
}

@Override
public AnnotationList getDeclaredAnnotations() {
return typeVariable.getDeclaredAnnotations();
}
}
} }


/** /**
Expand Down
31 changes: 31 additions & 0 deletions byte-buddy-dep/src/test/java/net/bytebuddy/Foo.java
@@ -0,0 +1,31 @@
package net.bytebuddy;

import net.bytebuddy.implementation.StubMethod;
import org.elasticsearch.client.Client;
import org.junit.Test;

import java.util.concurrent.Callable;

import static net.bytebuddy.matcher.ElementMatchers.any;

public class Foo {

@Test
public void testFoo() throws Exception {
new ByteBuddy().subclass(Client.class).method(any()).intercept(StubMethod.INSTANCE).make();
}

@Test
public void testBar() throws Exception {
new ByteBuddy().subclass(Qux.class).method(any()).intercept(StubMethod.INSTANCE).make();
}

interface Bar<T> {

<S> void bar(Callable<S> arg);
}

interface Qux extends Bar<Void> {

}
}
Expand Up @@ -20,7 +20,7 @@ public void testVisitType() throws Exception {


@Test @Test
public void testVisitMethod() throws Exception { public void testVisitMethod() throws Exception {
MethodDescription methodDescription = mock(MethodDescription.class); MethodDescription.InDefinedShape methodDescription = mock(MethodDescription.InDefinedShape.class);
assertThat(TypeVariableSource.Visitor.NoOp.INSTANCE.onMethod(methodDescription), is((TypeVariableSource) methodDescription)); assertThat(TypeVariableSource.Visitor.NoOp.INSTANCE.onMethod(methodDescription), is((TypeVariableSource) methodDescription));
} }


Expand Down

This file was deleted.

0 comments on commit 6732540

Please sign in to comment.