From 7d62291c96e0becde4821f29c4c4d610a8fe9426 Mon Sep 17 00:00:00 2001 From: Pontus Melke Date: Thu, 7 Jan 2016 08:12:50 +0100 Subject: [PATCH] Support for inner classes --- .../java/org/neo4j/codegen/ByteCodeUtils.java | 36 +++++++-- .../java/org/neo4j/codegen/ClassHandle.java | 2 +- .../java/org/neo4j/codegen/TypeReference.java | 75 +++++++++++++------ .../codegen/source/ClassByteCodeWriter.java | 8 +- .../org/neo4j/codegen/ByteCodeUtilsTest.java | 6 +- .../org/neo4j/codegen/CodeGenerationTest.java | 44 +++++++++++ .../java/org/neo4j/codegen/NamedBase.java | 65 ---------------- 7 files changed, 138 insertions(+), 98 deletions(-) delete mode 100644 community/codegen/src/test/java/org/neo4j/codegen/NamedBase.java diff --git a/community/codegen/src/main/java/org/neo4j/codegen/ByteCodeUtils.java b/community/codegen/src/main/java/org/neo4j/codegen/ByteCodeUtils.java index 1897a5d9c6c4d..9311c75300412 100644 --- a/community/codegen/src/main/java/org/neo4j/codegen/ByteCodeUtils.java +++ b/community/codegen/src/main/java/org/neo4j/codegen/ByteCodeUtils.java @@ -30,12 +30,34 @@ private ByteCodeUtils() 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 ) @@ -92,7 +114,7 @@ public static String[] exceptions( MethodDeclaration declaration ) { 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 ) @@ -187,7 +209,11 @@ private static StringBuilder internalType( StringBuilder builder, TypeReference { builder.append( packageName ).append( "/" ); } - builder.append( byteCodeName( name ) ); + if ( reference.isInnerClass() ) + { + builder.append( reference.declaringClassName() ).append( '$' ); + } + builder.append( name.replaceAll( "\\.", "\\/" ) ); } List parameters = reference.parameters(); diff --git a/community/codegen/src/main/java/org/neo4j/codegen/ClassHandle.java b/community/codegen/src/main/java/org/neo4j/codegen/ClassHandle.java index bc57805e4e611..7f3684c961cf1 100644 --- a/community/codegen/src/main/java/org/neo4j/codegen/ClassHandle.java +++ b/community/codegen/src/main/java/org/neo4j/codegen/ClassHandle.java @@ -27,7 +27,7 @@ public class ClassHandle extends TypeReference 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.generator = generator; this.generation = generation; diff --git a/community/codegen/src/main/java/org/neo4j/codegen/TypeReference.java b/community/codegen/src/main/java/org/neo4j/codegen/TypeReference.java index e925f1d25f0f9..2a625a9ee4ecd 100644 --- a/community/codegen/src/main/java/org/neo4j/codegen/TypeReference.java +++ b/community/codegen/src/main/java/org/neo4j/codegen/TypeReference.java @@ -60,7 +60,7 @@ public static TypeReference typeReference( Class type ) { return OBJECT; } - String packageName = "", simpleName; + String packageName = "", simpleName, declaringClassName = ""; if ( type.isArray() ) { simpleName = type.getComponentType().getCanonicalName() + "[]"; @@ -73,14 +73,24 @@ else if (type.isPrimitive()) { packageName = type.getPackage().getName(); 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 ) { - return new TypeReference( "", name, false, false, true ); + return new TypeReference( "", name, false, false, true, "" ); } public static TypeReference parameterizedType( Class base, Class... parameters ) @@ -95,7 +105,9 @@ public static TypeReference parameterizedType( Class base, TypeReference... p 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 ) @@ -125,6 +137,7 @@ public static TypeReference[] typeReferences( Class[] types ) private final boolean isPrimitive; private final boolean isArray; private final boolean isTypeParameter; + private final String declaringClassName; public String packageName() { @@ -146,18 +159,20 @@ public boolean 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]; TypeReference( String packageName, String simpleName, boolean isPrimitive, boolean isArray, - boolean isTypeParameter, TypeReference... parameters ) + boolean isTypeParameter, String declaringClassName, TypeReference... parameters ) { this.packageName = packageName; this.simpleName = simpleName; this.isPrimitive = isPrimitive; this.isArray = isArray; this.isTypeParameter = isTypeParameter; + this.declaringClassName = declaringClassName; this.parameters = parameters; } @@ -171,6 +186,31 @@ public List 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 public boolean equals( Object o ) { @@ -209,6 +249,10 @@ StringBuilder writeTo( StringBuilder result ) { result.append( packageName ).append( '.' ); } + if ( !declaringClassName.isEmpty() ) + { + result.append( declaringClassName ).append( '.' ); + } result.append( simpleName ); if ( !(parameters == null || parameters.length == 0) ) { @@ -224,21 +268,6 @@ StringBuilder writeTo( StringBuilder 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 { private final TypeReference type; diff --git a/community/codegen/src/main/java/org/neo4j/codegen/source/ClassByteCodeWriter.java b/community/codegen/src/main/java/org/neo4j/codegen/source/ClassByteCodeWriter.java index f257c8ec08684..be58705cac1ca 100644 --- a/community/codegen/src/main/java/org/neo4j/codegen/source/ClassByteCodeWriter.java +++ b/community/codegen/src/main/java/org/neo4j/codegen/source/ClassByteCodeWriter.java @@ -45,6 +45,7 @@ import static org.neo4j.codegen.ByteCodeUtils.byteCodeName; import static org.neo4j.codegen.ByteCodeUtils.desc; 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.typeName; import static org.objectweb.asm.Opcodes.AASTORE; @@ -104,10 +105,15 @@ class ClassByteCodeWriter implements ClassEmitter String[] iNames = new String[interfaces.length]; 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 ), 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.base = base; } diff --git a/community/codegen/src/test/java/org/neo4j/codegen/ByteCodeUtilsTest.java b/community/codegen/src/test/java/org/neo4j/codegen/ByteCodeUtilsTest.java index 773252eef8f7c..779ac291ee79d 100644 --- a/community/codegen/src/test/java/org/neo4j/codegen/ByteCodeUtilsTest.java +++ b/community/codegen/src/test/java/org/neo4j/codegen/ByteCodeUtilsTest.java @@ -185,11 +185,11 @@ public void shouldHandleGenericThrows() .throwsException( typeParameter( "E" ) ).build( owner ); // WHEN - String description = signature( declaration ); + String signature = signature( declaration ); String[] exceptions = exceptions( declaration ); // THEN - assertThat(description, - equalTo( "(Lorg/neo4j/codegen/CodeGenerationTest/Thrower;)V^TE;" )); + assertThat(signature, + equalTo( "(Lorg/neo4j/codegen/CodeGenerationTest$Thrower;)V^TE;" )); assertThat( exceptions, equalTo(new String[]{"java/lang/Exception"} )); } diff --git a/community/codegen/src/test/java/org/neo4j/codegen/CodeGenerationTest.java b/community/codegen/src/test/java/org/neo4j/codegen/CodeGenerationTest.java index 39c733ab5f4c3..1916fade45617 100644 --- a/community/codegen/src/test/java/org/neo4j/codegen/CodeGenerationTest.java +++ b/community/codegen/src/test/java/org/neo4j/codegen/CodeGenerationTest.java @@ -757,6 +757,50 @@ ClassGenerator generateClass( TypeReference base, String name, TypeReference... 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 void assertMethodReturningField( Class clazz, T argument ) throws Throwable { // given diff --git a/community/codegen/src/test/java/org/neo4j/codegen/NamedBase.java b/community/codegen/src/test/java/org/neo4j/codegen/NamedBase.java deleted file mode 100644 index 4e531e36ad4e3..0000000000000 --- a/community/codegen/src/test/java/org/neo4j/codegen/NamedBase.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2002-2016 "Neo Technology," - * Network Engine for Objects in Lund AB [http://neotechnology.com] - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.neo4j.codegen; - -@SuppressWarnings( "ALL" ) -public 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; - } -}