Skip to content

Commit

Permalink
METAGEN-35 Actual code changes and tests for the issue.
Browse files Browse the repository at this point in the history
  • Loading branch information
hferentschik authored and stliu committed Nov 11, 2013
1 parent d01ae40 commit 9dcc29c
Show file tree
Hide file tree
Showing 25 changed files with 265 additions and 67 deletions.
Expand Up @@ -31,16 +31,22 @@
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import javax.tools.Diagnostic;
import javax.tools.FileObject;

import org.hibernate.jpamodelgen.model.MetaAttribute;
import org.hibernate.jpamodelgen.model.MetaEntity;

/**
* Helper class to write the actual meta model class using the {@link javax.annotation.processing.Filer} API.
*
* @author Emmanuel Bernard
* @author Hardy Ferentschik
*/
public final class ClassWriter {
private static final String META_MODEL_CLASS_NAME_SUFFIX = "_";

private ClassWriter() {
}
Expand All @@ -51,7 +57,7 @@ public static void writeFile(MetaEntity entity, Context context) {
StringBuffer body = generateBody( entity, context );

FileObject fo = context.getProcessingEnvironment().getFiler().createSourceFile(
metaModelPackage + "." + entity.getSimpleName() + "_"
getFullyQualifiedClassName( entity, metaModelPackage )
);
OutputStream os = fo.openOutputStream();
PrintWriter pw = new PrintWriter( os );
Expand All @@ -63,7 +69,6 @@ public static void writeFile(MetaEntity entity, Context context) {

pw.flush();
pw.close();

}
catch ( FilerException filerEx ) {
context.logMessage(
Expand All @@ -87,15 +92,14 @@ public static void writeFile(MetaEntity entity, Context context) {
* @return body content
*/
private static StringBuffer generateBody(MetaEntity entity, Context context) {

StringWriter sw = new StringWriter();
PrintWriter pw = null;
try {
pw = new PrintWriter( sw );
if ( context.isAddGeneratedAnnotation() ) {
pw.println( "@" + entity.importType( Generated.class.getName() ) + "(\"JPA MetaModel for " + entity.getQualifiedName() + "\")" );
pw.println( writeGeneratedAnnotation( entity ) );
}
pw.println( "@" + entity.importType( "javax.persistence.metamodel.StaticMetamodel" ) + "(" + entity.getSimpleName() + ".class)" );
pw.println( writeStaticMetaModelAnnotation( entity ) );
printClassDeclaration( entity, pw, context );
pw.println();
List<MetaAttribute> members = entity.getMembers();
Expand All @@ -114,19 +118,62 @@ private static StringBuffer generateBody(MetaEntity entity, Context context) {
}

private static void printClassDeclaration(MetaEntity entity, PrintWriter pw, Context context) {
pw.print( "public abstract class " + entity.getSimpleName() + "_" );
pw.print( "public abstract class " + entity.getSimpleName() + META_MODEL_CLASS_NAME_SUFFIX );

final TypeMirror superClass = entity.getTypeElement().getSuperclass();
//superclass of Object is of NoType which returns some other kind
if ( superClass.getKind() == TypeKind.DECLARED ) {
//F..king Ch...t Have those people used their horrible APIs even once?
final Element superClassElement = ( ( DeclaredType ) superClass ).asElement();
String superClassName = ( ( TypeElement ) superClassElement ).getQualifiedName().toString();
if ( context.containsMetaEntity( superClassName )
|| context.containsMetaEmbeddable( superClassName ) ) {
pw.print( " extends " + superClassName + "_" );
final Element superClassElement = ( (DeclaredType) superClass ).asElement();
String superClassName = ( (TypeElement) superClassElement ).getQualifiedName().toString();
if ( extendsSuperMetaModel( superClassElement, entity.isMetaComplete(), context ) ) {
pw.print( " extends " + superClassName + META_MODEL_CLASS_NAME_SUFFIX );
}
}
pw.println( " {" );
}

/**
* Checks whether this metamodel class needs to extend another metamodel class.
* This methods checks whether the processor has generated a metamodel class for the super class, but it also
* allows for the possibility that the metamodel class was generated in a previous compilation (eg it could be
* part of a separate jar. See also METAGEN-35).
*
* @param superClassElement the super class element
* @param entityMetaComplete flag indicating if the entity for which the metamodel should be generarted is metamodel
* complete. If so we cannot use reflection to decide whether we have to add the extend clause
* @param context the execution context
*
* @return {@code true} in case there is super class meta model to extend from {@code false} otherwise.
*/
private static boolean extendsSuperMetaModel(Element superClassElement, boolean entityMetaComplete, Context context) {
// if we processed the superclass in the same run we definitely need to extend
String superClassName = ( (TypeElement) superClassElement ).getQualifiedName().toString();
if ( context.containsMetaEntity( superClassName )
|| context.containsMetaEmbeddable( superClassName ) ) {
return true;
}

// to allow for the case that the metamodel class for the super entity is for example contained in another
// jar file we use reflection. However, we need to consider the fact that there is xml configuration
// and annotations should be ignored
if ( !entityMetaComplete && ( superClassElement.getAnnotation( Entity.class ) != null
|| superClassElement.getAnnotation( MappedSuperclass.class ) != null ) ) {
return true;
}

return false;
}

private static String getFullyQualifiedClassName(MetaEntity entity, String metaModelPackage) {
return metaModelPackage + "." + entity.getSimpleName() + META_MODEL_CLASS_NAME_SUFFIX;
}

private static String writeGeneratedAnnotation(MetaEntity entity) {
return "@" + entity.importType( Generated.class.getName() ) + "(\"JPA MetaModel for " + entity.getQualifiedName() + "\")";
}

private static String writeStaticMetaModelAnnotation(MetaEntity entity) {
return "@" + entity.importType( "javax.persistence.metamodel.StaticMetamodel" ) + "(" + entity.getSimpleName() + ".class)";
}
}
Expand Up @@ -27,7 +27,7 @@
/**
* @author Hardy Ferentschik
*/
public class Constants {
public final class Constants {
public static Map<String, String> COLLECTIONS = new HashMap<String, String>();

static {
Expand Down
Expand Up @@ -22,7 +22,7 @@
/**
* @author Hardy Ferentschik
*/
public class StringUtil {
public final class StringUtil {
private static final String NAME_SEPARATOR = ".";
private static final String PROPERTY_PREFIX_GET = "get";
private static final String PROPERTY_PREFIX_IS = "is";
Expand Down Expand Up @@ -63,16 +63,17 @@ public static String getPropertyName(String name) {
return null;
}

String tmp = name;
if ( name.startsWith( PROPERTY_PREFIX_GET ) ) {
name = name.replaceFirst( PROPERTY_PREFIX_GET, "" );
tmp = name.replaceFirst( PROPERTY_PREFIX_GET, "" );
}
else if ( name.startsWith( PROPERTY_PREFIX_IS ) ) {
name = name.replaceFirst( PROPERTY_PREFIX_IS, "" );
tmp = name.replaceFirst( PROPERTY_PREFIX_IS, "" );
}
else if ( name.startsWith( PROPERTY_PREFIX_HAS ) ) {
name = name.replaceFirst( PROPERTY_PREFIX_HAS, "" );
tmp = name.replaceFirst( PROPERTY_PREFIX_HAS, "" );
}
return name.substring(0,1).toLowerCase() + name.substring(1);
return tmp.substring(0,1).toLowerCase() + tmp.substring(1);
}
}

Expand Down
Expand Up @@ -124,7 +124,7 @@ private XmlMetaEntity(String clazz, String defaultPackageName, TypeElement eleme
this.isMetaComplete = initIsMetaComplete( metaComplete );
}

protected void init() {
protected final void init() {
this.accessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
if ( attributes != null ) {
parseAttributes( attributes );
Expand Down
Expand Up @@ -99,7 +99,7 @@ public void testMemberAccessType() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return AccessTypeTest.class.getPackage().getName();
}

Expand Down
Expand Up @@ -49,7 +49,7 @@ public void testIntegerArray() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return Image.class.getPackage().getName();
}
}
Expand Up @@ -40,7 +40,7 @@ public void testBlobField() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return BlobTest.class.getPackage().getName();
}
}
Expand Up @@ -78,7 +78,7 @@ public void testMapKeyClassXmlConfigured() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return ElementCollectionTest.class.getPackage().getName();
}

Expand Down
Expand Up @@ -40,7 +40,7 @@ public void testMetaModelsGenerated() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return EmbeddableMappedSuperClassTest.class.getPackage().getName();
}
}
Expand Up @@ -42,7 +42,7 @@ public void testGeneratedAnnotationNotGenerated() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return GeneratedAnnotationTest.class.getPackage().getName();
}
}
Expand Up @@ -56,7 +56,7 @@ protected Map<String, String> getProcessorOptions() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return GeneratedAnnotationTest2.class.getPackage().getName();
}
}
Expand Up @@ -37,7 +37,7 @@ public void testGenerics() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return GenericsTest.class.getPackage().getName();
}
}
Expand Up @@ -52,7 +52,7 @@ public void testInheritance() throws Exception {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return InheritanceTest.class.getPackage().getName();
}
}
Expand Up @@ -96,7 +96,7 @@ public void testAccessTypeForXmlConfiguredEmbeddables() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return MixedConfigurationTest.class.getPackage().getName();
}

Expand Down
Expand Up @@ -42,7 +42,7 @@ public void testXmlConfiguredEmbeddedClassGenerated() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return XmlMetaCompleteTest.class.getPackage().getName();
}

Expand Down
Expand Up @@ -37,7 +37,7 @@ public void testGenerics() {
}

@Override
protected String getPackageNameOfTestSources() {
protected String getPackageNameOfCurrentTest() {
return DeskWithRawType.class.getPackage().getName();
}
}
@@ -0,0 +1,31 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// $Id:$
package org.hibernate.jpamodelgen.test.separatecompilationunits;

import org.hibernate.jpamodelgen.test.separatecompilationunits.superclass.MappedSuperclass;

/**
* @author Hardy Ferentschik
*/
@javax.persistence.Entity
public class Entity extends MappedSuperclass {
private String name;
}


@@ -0,0 +1,68 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// $Id$

package org.hibernate.jpamodelgen.test.separatecompilationunits;

import java.io.File;
import java.util.List;

import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import org.hibernate.jpamodelgen.test.util.CompilationTest;

import static org.hibernate.jpamodelgen.test.util.TestUtil.getMetaModelSourceAsString;
import static org.testng.Assert.assertTrue;

/**
* @author Hardy Ferentschik
* @see METAGEN-35
*/
public class SeparateCompilationUnitsTest extends CompilationTest {
@Test
public void testInheritance() throws Exception {
// need to work with the source file. Entity_.class won't get generated, because the mapped superclass
// will not be on the classpath
String entityMetaModel = getMetaModelSourceAsString( Entity.class );
assertTrue(
entityMetaModel.contains(
"extends org.hibernate.jpamodelgen.test.separatecompilationunits.superclass.MappedSuperclass"
)
);
}

@Override
@BeforeClass
// override compileAllTestEntities to compile the mapped super class explicitly
protected void compileAllTestEntities() throws Exception {
String superClassPackageName = getPackageNameOfCurrentTest() + ".superclass";
List<File> sourceFiles = getCompilationUnits(
CompilationTest.getSourceBaseDir(), superClassPackageName
);
compile( sourceFiles, superClassPackageName );

sourceFiles = getCompilationUnits( getSourceBaseDir(), getPackageNameOfCurrentTest() );
compile( sourceFiles, getPackageNameOfCurrentTest() );
}

@Override
protected String getPackageNameOfCurrentTest() {
return SeparateCompilationUnitsTest.class.getPackage().getName();
}
}

0 comments on commit 9dcc29c

Please sign in to comment.