diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java index 75d1fe5d10..435c6ec0a2 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java @@ -40,7 +40,7 @@ import org.hibernate.jpamodelgen.util.Constants; * @author Hardy Ferentschik * @author Emmanuel Bernard */ -public class Context { +public final class Context { private static final String DEFAULT_PERSISTENCE_XML_LOCATION = "/META-INF/persistence.xml"; /** diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java index cbb3363250..f996c1e890 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java @@ -19,6 +19,7 @@ package org.hibernate.jpamodelgen; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -139,19 +140,28 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { } private void createMetaModelClasses() { + // keep track of all classes for which model have been generated + Collection generatedModelClasses = new ArrayList(); + for ( MetaEntity entity : context.getMetaEntities() ) { context.logMessage( Diagnostic.Kind.OTHER, "Writing meta model for entity " + entity ); ClassWriter.writeFile( entity, context ); + generatedModelClasses.add( entity.getQualifiedName() ); } // we cannot process the delayed entities in any order. There might be dependencies between them. // we need to process the top level entities first - // TODO make sure that we don't run into circular dependencies here Collection toProcessEntities = context.getMetaEmbeddables(); while ( !toProcessEntities.isEmpty() ) { Set processedEntities = new HashSet(); + int toProcessCountBeforeLoop = toProcessEntities.size(); for ( MetaEntity entity : toProcessEntities ) { - if ( containedInEntity( toProcessEntities, entity ) ) { + // see METAGEN-36 + if ( generatedModelClasses.contains( entity.getQualifiedName() ) ) { + toProcessEntities.remove( entity ); + continue; + } + if ( modelGenerationNeedsToBeDeferred( toProcessEntities, entity ) ) { continue; } context.logMessage( @@ -161,10 +171,15 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { processedEntities.add( entity ); } toProcessEntities.removeAll( processedEntities ); + if ( toProcessEntities.size() >= toProcessCountBeforeLoop ) { + context.logMessage( + Diagnostic.Kind.ERROR, "Potential endless loop in generation of entities." + ); + } } } - private boolean containedInEntity(Collection entities, MetaEntity containedEntity) { + private boolean modelGenerationNeedsToBeDeferred(Collection entities, MetaEntity containedEntity) { ContainsAttributeTypeVisitor visitor = new ContainsAttributeTypeVisitor( containedEntity.getTypeElement(), context ); @@ -207,7 +222,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { continue; } - String fqn = ( ( TypeElement ) element ).getQualifiedName().toString(); + String fqn = ( (TypeElement) element ).getQualifiedName().toString(); MetaEntity alreadyExistingMetaEntity = tryGettingExistingEntityFromContext( mirror, fqn ); if ( alreadyExistingMetaEntity != null && alreadyExistingMetaEntity.isMetaComplete() ) { String msg = "Skipping processing of annotations for " + fqn + " since xml configuration is metadata complete."; @@ -217,10 +232,10 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { AnnotationMetaEntity metaEntity; if ( TypeUtils.containsAnnotation( element, Embeddable.class ) ) { - metaEntity = new AnnotationEmbeddable( ( TypeElement ) element, context ); + metaEntity = new AnnotationEmbeddable( (TypeElement) element, context ); } else { - metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context ); + metaEntity = new AnnotationMetaEntity( (TypeElement) element, context ); } if ( alreadyExistingMetaEntity != null ) { @@ -267,7 +282,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { @Override public Boolean visitDeclared(DeclaredType declaredType, Element element) { - TypeElement returnedElement = ( TypeElement ) context.getTypeUtils().asElement( declaredType ); + TypeElement returnedElement = (TypeElement) context.getTypeUtils().asElement( declaredType ); String fqNameOfReturnType = returnedElement.getQualifiedName().toString(); String collection = Constants.COLLECTIONS.get( fqNameOfReturnType ); @@ -275,7 +290,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { TypeMirror collectionElementType = TypeUtils.getCollectionElementType( declaredType, fqNameOfReturnType, null, context ); - returnedElement = ( TypeElement ) context.getTypeUtils().asElement( collectionElementType ); + returnedElement = (TypeElement) context.getTypeUtils().asElement( collectionElementType ); } if ( type.getQualifiedName().toString().equals( returnedElement.getQualifiedName().toString() ) ) { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java index f98f8f1a2a..6f8f62d4c0 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java @@ -133,7 +133,7 @@ public class AnnotationMetaEntity implements MetaEntity { sb.append( '}' ); return sb.toString(); } - + private void addPersistentMembers(List membersOfClass, AccessType membersKind) { for ( Element memberOfClass : membersOfClass ) { AccessType forcedAccessType = TypeUtils.determineAnnotationSpecifiedAccessType( memberOfClass ); diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/embeddablemappedsuperclass/EmbeddableAndMappedSuperClass.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/embeddablemappedsuperclass/EmbeddableAndMappedSuperClass.java new file mode 100644 index 0000000000..dfbc30eb5a --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/embeddablemappedsuperclass/EmbeddableAndMappedSuperClass.java @@ -0,0 +1,33 @@ +/* + * 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.embeddablemappedsuperclass; + +import javax.persistence.Embeddable; +import javax.persistence.MappedSuperclass; + +/** + * @author Hardy Ferentschik + */ +@Embeddable +@MappedSuperclass +public class EmbeddableAndMappedSuperClass { + +} + + diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/embeddablemappedsuperclass/EmbeddableMappedSuperClassTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/embeddablemappedsuperclass/EmbeddableMappedSuperClassTest.java new file mode 100644 index 0000000000..c3e3a6b6f2 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/embeddablemappedsuperclass/EmbeddableMappedSuperClassTest.java @@ -0,0 +1,46 @@ +/* + * 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: BlobTest.java 20721 2010-09-27 12:40:10Z hardy.ferentschik $ + +package org.hibernate.jpamodelgen.test.embeddablemappedsuperclass; + +import org.testng.annotations.Test; + +import org.hibernate.jpamodelgen.test.util.CompilationTest; + +import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor; +import static org.hibernate.jpamodelgen.test.util.TestUtil.assertNoCompilationError; + +/** + * @author Hardy Ferentschik + */ +public class EmbeddableMappedSuperClassTest extends CompilationTest { + /** + * METAGEN-36 + */ + @Test + public void testMetaModelsGenerated() { + assertMetamodelClassGeneratedFor( EmbeddableAndMappedSuperClass.class ); + assertNoCompilationError(getCompilationDiagnostics()); + } + + @Override + protected String getPackageNameOfTestSources() { + return EmbeddableMappedSuperClassTest.class.getPackage().getName(); + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java index c1394deb98..8e697a70dd 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java @@ -43,17 +43,22 @@ import org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor; import static org.testng.FileAssert.fail; /** + * Base class for annotation processor tests. + * * @author Hardy Ferentschik */ public abstract class CompilationTest { private static final Logger log = LoggerFactory.getLogger( CompilationTest.class ); private static final String PATH_SEPARATOR = System.getProperty( "file.separator" ); private static final String ANNOTATION_PROCESSOR_OPTION_PREFIX = "-A"; + private static final String PROC_NONE = "-proc:none"; private static final String SOURCE_BASE_DIR_PROPERTY = "sourceBaseDir"; private static final String OUT_BASE_DIR_PROPERTY = "outBaseDir"; private static final String sourceBaseDir; private static final String outBaseDir; + private List compilationDiagnostics; + static { String tmp = System.getProperty( SOURCE_BASE_DIR_PROPERTY ); if ( tmp == null ) { @@ -69,6 +74,11 @@ public abstract class CompilationTest { } public CompilationTest() { + compilationDiagnostics = new ArrayList(); + } + + public final List getCompilationDiagnostics() { + return compilationDiagnostics; } @BeforeClass @@ -91,8 +101,9 @@ public abstract class CompilationTest { compilationUnits = fileManager.getJavaFileObjectsFromFiles( getCompilationUnits( outBaseDir ) ); - options.add( "-proc:none" ); // for the second compile skip the processor + options.add( PROC_NONE ); // for the second compile skip the processor compileSources( options, compiler, diagnostics, fileManager, compilationUnits ); + compilationDiagnostics.addAll( diagnostics.getDiagnostics() ); fileManager.close(); } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java index 2ac9c05302..136fcf3785 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java @@ -28,6 +28,8 @@ import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.List; +import javax.tools.Diagnostic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -209,10 +211,6 @@ public class TestUtil { } } - private static boolean hasFieldInMetamodelFor(Class clazz, String fieldName) { - return getFieldFromMetamodelFor( clazz, fieldName ) != null; - } - public static Field getFieldFromMetamodelFor(Class entityClass, String fieldName) { Class metaModelClass = getMetamodelClassFor( entityClass ); Field field; @@ -229,6 +227,18 @@ public class TestUtil { return fcn.replace( PACKAGE_SEPARATOR, PATH_SEPARATOR ); } + public static void assertNoCompilationError(List diagnostics) { + for ( Diagnostic diagnostic : diagnostics ) { + if ( diagnostic.getKind().equals( Diagnostic.Kind.ERROR ) ) { + fail( "There was a compilation error. " + diagnostic.getMessage( null ) ); + } + } + } + + private static boolean hasFieldInMetamodelFor(Class clazz, String fieldName) { + return getFieldFromMetamodelFor( clazz, fieldName ) != null; + } + private static class MetaModelFilenameFilter implements FileFilter { @Override public boolean accept(File pathName) {