Skip to content

Commit

Permalink
Support for inner classes
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusmelke committed May 17, 2016
1 parent dee1eb4 commit 7d62291
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 98 deletions.
Expand Up @@ -30,12 +30,34 @@ private ByteCodeUtils()


public static String byteCodeName( TypeReference reference ) public static String byteCodeName( TypeReference reference )
{ {
return byteCodeName( reference.name() ); StringBuilder builder = new StringBuilder();
if ( !reference.packageName().isEmpty() )
{
builder.append( reference.packageName().replaceAll( "\\.", "/" ) ).append( '/' );
}
if ( reference.isInnerClass() )
{
builder.append( reference.declaringClassName() ).append( '$' );
}
builder.append( reference.simpleName() );
return builder.toString();
} }


public static String byteCodeName( String javaName ) public static String outerName( TypeReference reference )
{ {
return javaName.replaceAll( "\\.", "\\/" ); if (!reference.isInnerClass())
{
return null;
}

StringBuilder builder = new StringBuilder();
if ( !reference.packageName().isEmpty() )
{
builder.append( reference.packageName().replaceAll( "\\.", "/" ) ).append( '/' );
}
builder.append( reference.simpleName() );

return builder.toString();
} }


public static String typeName( TypeReference reference ) public static String typeName( TypeReference reference )
Expand Down Expand Up @@ -92,7 +114,7 @@ public static String[] exceptions( MethodDeclaration declaration )
{ {
return null; return null;
} }
return throwsList.stream().map( e -> byteCodeName( e.name() ) ).toArray( String[]::new ); return throwsList.stream().map( ByteCodeUtils::byteCodeName ).toArray( String[]::new );
} }


private static String internalDesc( MethodDeclaration declaration, boolean showErasure ) private static String internalDesc( MethodDeclaration declaration, boolean showErasure )
Expand Down Expand Up @@ -187,7 +209,11 @@ private static StringBuilder internalType( StringBuilder builder, TypeReference
{ {
builder.append( packageName ).append( "/" ); builder.append( packageName ).append( "/" );
} }
builder.append( byteCodeName( name ) ); if ( reference.isInnerClass() )
{
builder.append( reference.declaringClassName() ).append( '$' );
}
builder.append( name.replaceAll( "\\.", "\\/" ) );
} }


List<TypeReference> parameters = reference.parameters(); List<TypeReference> parameters = reference.parameters();
Expand Down
Expand Up @@ -27,7 +27,7 @@ public class ClassHandle extends TypeReference


ClassHandle( String packageName, String name, TypeReference parent, CodeGenerator generator, long generation ) ClassHandle( String packageName, String name, TypeReference parent, CodeGenerator generator, long generation )
{ {
super(packageName, name, parent.isPrimitive(), parent.isArray(), false ); super(packageName, name, parent.isPrimitive(), parent.isArray(), false, "");
this.parent = parent; this.parent = parent;
this.generator = generator; this.generator = generator;
this.generation = generation; this.generation = generation;
Expand Down
Expand Up @@ -60,7 +60,7 @@ public static TypeReference typeReference( Class<?> type )
{ {
return OBJECT; return OBJECT;
} }
String packageName = "", simpleName; String packageName = "", simpleName, declaringClassName = "";
if ( type.isArray() ) if ( type.isArray() )
{ {
simpleName = type.getComponentType().getCanonicalName() + "[]"; simpleName = type.getComponentType().getCanonicalName() + "[]";
Expand All @@ -73,14 +73,24 @@ else if (type.isPrimitive())
{ {
packageName = type.getPackage().getName(); packageName = type.getPackage().getName();
String canonicalName = type.getCanonicalName(); String canonicalName = type.getCanonicalName();
simpleName = canonicalName.substring( packageName.length() + 1 ); Class<?> declaringClass = type.getDeclaringClass();
if ( declaringClass != null)
{
declaringClassName = declaringClass.getSimpleName();
simpleName = canonicalName.substring( packageName.length() + declaringClassName.length() + 2 );
}
else
{
simpleName = canonicalName.substring( packageName.length() + 1 );
}
} }
return new TypeReference( packageName, simpleName, type.isPrimitive(), type.isArray(), false ); return new TypeReference( packageName, simpleName, type.isPrimitive(), type.isArray(), false,
declaringClassName );
} }


public static TypeReference typeParameter( String name ) public static TypeReference typeParameter( String name )
{ {
return new TypeReference( "", name, false, false, true ); return new TypeReference( "", name, false, false, true, "" );
} }


public static TypeReference parameterizedType( Class<?> base, Class<?>... parameters ) public static TypeReference parameterizedType( Class<?> base, Class<?>... parameters )
Expand All @@ -95,7 +105,9 @@ public static TypeReference parameterizedType( Class<?> base, TypeReference... p


public static TypeReference parameterizedType( TypeReference base, TypeReference... parameters ) public static TypeReference parameterizedType( TypeReference base, TypeReference... parameters )
{ {
return new TypeReference( base.packageName, base.simpleName, false, base.isArray(), false, parameters ); return new TypeReference( base.packageName, base.simpleName, false, base.isArray(), false,
base.declaringClassName,
parameters );
} }


public static TypeReference[] typeReferences( Class<?> first, Class<?>[] more ) public static TypeReference[] typeReferences( Class<?> first, Class<?>[] more )
Expand Down Expand Up @@ -125,6 +137,7 @@ public static TypeReference[] typeReferences( Class<?>[] types )
private final boolean isPrimitive; private final boolean isPrimitive;
private final boolean isArray; private final boolean isArray;
private final boolean isTypeParameter; private final boolean isTypeParameter;
private final String declaringClassName;


public String packageName() public String packageName()
{ {
Expand All @@ -146,18 +159,20 @@ public boolean isTypeParameter()
return isTypeParameter; return isTypeParameter;
} }


public static final TypeReference VOID = new TypeReference( "", "void", true, false, false ),
OBJECT = new TypeReference( "java.lang", "Object", false, false, false ); public static final TypeReference VOID = new TypeReference( "", "void", true, false, false, "" ),
OBJECT = new TypeReference( "java.lang", "Object", false, false, false, "" );
static final TypeReference[] NO_TYPES = new TypeReference[0]; static final TypeReference[] NO_TYPES = new TypeReference[0];


TypeReference( String packageName, String simpleName, boolean isPrimitive, boolean isArray, TypeReference( String packageName, String simpleName, boolean isPrimitive, boolean isArray,
boolean isTypeParameter, TypeReference... parameters ) boolean isTypeParameter, String declaringClassName, TypeReference... parameters )
{ {
this.packageName = packageName; this.packageName = packageName;
this.simpleName = simpleName; this.simpleName = simpleName;
this.isPrimitive = isPrimitive; this.isPrimitive = isPrimitive;
this.isArray = isArray; this.isArray = isArray;
this.isTypeParameter = isTypeParameter; this.isTypeParameter = isTypeParameter;
this.declaringClassName = declaringClassName;
this.parameters = parameters; this.parameters = parameters;
} }


Expand All @@ -171,6 +186,31 @@ public List<TypeReference> parameters()
return unmodifiableList( asList( parameters ) ); return unmodifiableList( asList( parameters ) );
} }


public String name()
{
return writeTo( new StringBuilder() ).toString();
}

public boolean isArray()
{
return isArray;
}

public boolean isVoid()
{
return this == VOID;
}

public boolean isInnerClass()
{
return !declaringClassName.isEmpty();
}

public String declaringClassName()
{
return declaringClassName;
}

@Override @Override
public boolean equals( Object o ) public boolean equals( Object o )
{ {
Expand Down Expand Up @@ -209,6 +249,10 @@ StringBuilder writeTo( StringBuilder result )
{ {
result.append( packageName ).append( '.' ); result.append( packageName ).append( '.' );
} }
if ( !declaringClassName.isEmpty() )
{
result.append( declaringClassName ).append( '.' );
}
result.append( simpleName ); result.append( simpleName );
if ( !(parameters == null || parameters.length == 0) ) if ( !(parameters == null || parameters.length == 0) )
{ {
Expand All @@ -224,21 +268,6 @@ StringBuilder writeTo( StringBuilder result )
return result; return result;
} }


public String name()
{
return writeTo( new StringBuilder() ).toString();
}

public boolean isArray()
{
return isArray;
}

public boolean isVoid()
{
return this == VOID;
}

public abstract static class Bound public abstract static class Bound
{ {
private final TypeReference type; private final TypeReference type;
Expand Down
Expand Up @@ -45,6 +45,7 @@
import static org.neo4j.codegen.ByteCodeUtils.byteCodeName; import static org.neo4j.codegen.ByteCodeUtils.byteCodeName;
import static org.neo4j.codegen.ByteCodeUtils.desc; import static org.neo4j.codegen.ByteCodeUtils.desc;
import static org.neo4j.codegen.ByteCodeUtils.exceptions; import static org.neo4j.codegen.ByteCodeUtils.exceptions;
import static org.neo4j.codegen.ByteCodeUtils.outerName;
import static org.neo4j.codegen.ByteCodeUtils.signature; import static org.neo4j.codegen.ByteCodeUtils.signature;
import static org.neo4j.codegen.ByteCodeUtils.typeName; import static org.neo4j.codegen.ByteCodeUtils.typeName;
import static org.objectweb.asm.Opcodes.AASTORE; import static org.objectweb.asm.Opcodes.AASTORE;
Expand Down Expand Up @@ -104,10 +105,15 @@ class ClassByteCodeWriter implements ClassEmitter
String[] iNames = new String[interfaces.length]; String[] iNames = new String[interfaces.length];
for ( int i = 0; i < interfaces.length; i++ ) for ( int i = 0; i < interfaces.length; i++ )
{ {
iNames[i] = byteCodeName( interfaces[i].name() ); iNames[i] = byteCodeName( interfaces[i] );
} }
classWriter.visit( V1_8, ACC_PUBLIC + ACC_SUPER, byteCodeName( type ), signature( type ), classWriter.visit( V1_8, ACC_PUBLIC + ACC_SUPER, byteCodeName( type ), signature( type ),
byteCodeName( base ), iNames.length != 0 ? iNames : null ); byteCodeName( base ), iNames.length != 0 ? iNames : null );
if ( base.isInnerClass() )
{
classWriter.visitInnerClass( byteCodeName( base ), outerName(base),
base.simpleName() , ACC_PUBLIC + ACC_STATIC );
}
this.type = type; this.type = type;
this.base = base; this.base = base;
} }
Expand Down
Expand Up @@ -185,11 +185,11 @@ public void shouldHandleGenericThrows()
.throwsException( typeParameter( "E" ) ).build( owner ); .throwsException( typeParameter( "E" ) ).build( owner );


// WHEN // WHEN
String description = signature( declaration ); String signature = signature( declaration );
String[] exceptions = exceptions( declaration ); String[] exceptions = exceptions( declaration );
// THEN // THEN
assertThat(description, assertThat(signature,
equalTo( "<E:Ljava/lang/Exception;>(Lorg/neo4j/codegen/CodeGenerationTest/Thrower<TE;>;)V^TE;" )); equalTo( "<E:Ljava/lang/Exception;>(Lorg/neo4j/codegen/CodeGenerationTest$Thrower<TE;>;)V^TE;" ));
assertThat( exceptions, equalTo(new String[]{"java/lang/Exception"} )); assertThat( exceptions, equalTo(new String[]{"java/lang/Exception"} ));
} }


Expand Down
Expand Up @@ -757,6 +757,50 @@ ClassGenerator generateClass( TypeReference base, String name, TypeReference...
return generator.generateClass( base, PACKAGE, name, interfaces ); return generator.generateClass( base, PACKAGE, name, interfaces );
} }


public static class NamedBase
{
final String name;
private boolean defaultConstructorCalled = false;
private String foo;
private String bar;

public NamedBase()
{
this.defaultConstructorCalled = true;
this.name = null;
}

public NamedBase( String name )
{
this.name = name;
}

public boolean defaultConstructorCalled()
{
return defaultConstructorCalled;
}

public String getFoo()
{
return foo;
}

public String getBar()
{
return bar;
}

public void setFoo( String foo )
{
this.foo = foo;
}

public void setBar( String bar )
{
this.bar = bar;
}
}

private <T> void assertMethodReturningField( Class<T> clazz, T argument ) throws Throwable private <T> void assertMethodReturningField( Class<T> clazz, T argument ) throws Throwable
{ {
// given // given
Expand Down
65 changes: 0 additions & 65 deletions community/codegen/src/test/java/org/neo4j/codegen/NamedBase.java

This file was deleted.

0 comments on commit 7d62291

Please sign in to comment.