From d953449b3ab104ea6dfc643e789f2fa74941de92 Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Wed, 27 Apr 2011 15:36:56 +0200 Subject: [PATCH] HHH-6161 Taking care of added package names via MetadataSources.addPackage --- .../metamodel/source/MetadataSources.java | 23 +++-- .../source/annotations/AnnotationBinder.java | 14 ++- .../global/FetchProfileBinder.java | 2 +- .../util/ConfiguredClassHierarchyBuilder.java | 11 +++ .../source/internal/MetadataImpl.java | 39 +++++--- .../metamodel/source/internal/Foo.java | 32 +++++++ .../source/internal/MetadataImplTest.java | 93 +++++++++++++++++++ .../source/internal/package-info.java | 31 +++++++ 8 files changed, 222 insertions(+), 23 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/Foo.java create mode 100644 hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/MetadataImplTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/package-info.java diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/MetadataSources.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/MetadataSources.java index 0ae7d2371c..4b5be21189 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/MetadataSources.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/MetadataSources.java @@ -120,11 +120,17 @@ public class MetadataSources { /** * Read package-level metadata. * - * @param packageName java package name + * @param packageName java package name without trailing '.', cannot be {@code null} * * @return this (for method chaining) */ public MetadataSources addPackage(String packageName) { + if ( packageName == null ) { + throw new IllegalArgumentException( "The specified package name cannot be null" ); + } + if ( packageName.endsWith( "." ) ) { + packageName = packageName.substring( 0, packageName.length() - 1 ); + } annotatedPackages.add( packageName ); return this; } @@ -175,11 +181,14 @@ public class MetadataSources { * Read a mapping as an application resource using the convention that a class named {@code foo.bar.Foo} is * mapped by a file named {@code foo/bar/Foo.hbm.xml} which can be resolved as a classpath resource. * - * @param entityClass The mapped class + * @param entityClass The mapped class. Cannot be {@code null} null. * * @return this (for method chaining purposes) */ public MetadataSources addClass(Class entityClass) { + if ( entityClass == null ) { + throw new IllegalArgumentException( "The specified class cannot be null" ); + } LOG.debugf( "adding resource mappings from class convention : %s", entityClass.getName() ); final String mappingResourceName = entityClass.getName().replace( '.', '/' ) + ".hbm.xml"; addResource( mappingResourceName ); @@ -207,7 +216,7 @@ public class MetadataSources { * @return this (for method chaining purposes) */ public MetadataSources addFile(File file) { - final String name = file.getAbsolutePath(); + final String name = file.getAbsolutePath(); LOG.tracef( "reading mappings from file : %s", name ); final Origin origin = new Origin( SourceType.FILE, name ); try { @@ -319,7 +328,7 @@ public class MetadataSources { try { add( jarFile.getInputStream( zipEntry ), origin, true ); } - catch (Exception e) { + catch ( Exception e ) { throw new MappingException( "could not read mapping documents", e, origin ); } } @@ -329,11 +338,11 @@ public class MetadataSources { try { jarFile.close(); } - catch (Exception ignore) { + catch ( Exception ignore ) { } } } - catch (IOException e) { + catch ( IOException e ) { throw new MappingNotFoundException( e, origin ); } return this; @@ -345,7 +354,9 @@ public class MetadataSources { * Assumes that any file named *.hbm.xml is a mapping document. * * @param dir The directory + * * @return this (for method chaining purposes) + * * @throws org.hibernate.MappingException Indicates problems reading the jar file or * processing the contained mapping documents. */ diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java index ebe731d3a5..05c7127dc0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java @@ -26,11 +26,11 @@ package org.hibernate.metamodel.source.annotations; import java.util.Iterator; import java.util.Set; -import org.jboss.jandex.ClassInfo; import org.jboss.jandex.Index; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.hibernate.metamodel.source.annotations.global.FetchProfileBinder; import org.hibernate.metamodel.source.annotations.util.ConfiguredClassHierarchyBuilder; import org.hibernate.metamodel.source.internal.MetadataImpl; @@ -51,6 +51,16 @@ public class AnnotationBinder { this.metadata = metadata; } + /** + * Binds global configuration data. This includes mappings which live outside of the configuration for a single + * entity or entity hierarchy, for example sequence generators, fetch profiles, etc + * + * @param annotationIndex the annotation repository/index + */ + public void bindGlobalAnnotations(Index annotationIndex) { + FetchProfileBinder.bindFetchProfiles( metadata, annotationIndex ); + } + public void bindMappedClasses(Index annotationIndex) { // need to order our annotated entities into an order we can process Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( @@ -79,8 +89,6 @@ public class AnnotationBinder { // PersistentClass persistentClass = makePersistentClass( inheritanceState, superEntity ); - - // entityBinder.setInheritanceState( inheritanceState ); // // bindQueries( clazzToProcess, mappings ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java index b52eb8a704..9f299a833c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java @@ -67,7 +67,7 @@ public class FetchProfileBinder { bindFetchProfileAnnotations( meta, fetchProfileAnnotations ); } - public static void bindFetchProfileAnnotations(MetadataImpl meta, List fetchProfileAnnotations) { + private static void bindFetchProfileAnnotations(MetadataImpl meta, List fetchProfileAnnotations) { for ( AnnotationInstance fetchProfileAnnotation : fetchProfileAnnotations ) { String name = fetchProfileAnnotation.value( "name" ).asString(); FetchProfile profile = meta.findOrCreateFetchProfile( name, MetadataSource.ANNOTATIONS ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilder.java index bf5aa190c8..2ff26b79c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilder.java @@ -30,11 +30,13 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; import org.jboss.jandex.Index; import org.hibernate.metamodel.source.annotations.ConfiguredClassHierarchy; +import org.hibernate.metamodel.source.annotations.JPADotNames; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.classloading.spi.ClassLoaderService; @@ -59,6 +61,15 @@ public class ConfiguredClassHierarchyBuilder { Map> processedClassInfos = new HashMap>(); for ( ClassInfo info : index.getKnownClasses() ) { + AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( info, JPADotNames.ENTITY ); + AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation( + info, JPADotNames.MAPPED_SUPER_CLASS + ); + // we are only interested in building the class hierarchies for @Entity or @MappedSuperclass w + if ( jpaEntityAnnotation == null && mappedSuperClassAnnotation == null ) { + continue; + } + if ( processedClassInfos.containsKey( info ) ) { continue; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java index ae028c4e34..8ebaa1b260 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java @@ -53,6 +53,7 @@ import org.hibernate.metamodel.source.hbm.HibernateXmlBinder; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping; import org.hibernate.metamodel.source.spi.MetadataImplementor; import org.hibernate.service.BasicServiceRegistry; +import org.hibernate.service.classloading.spi.ClassLoaderService; /** * Container for configuration data while building and binding the metamodel @@ -103,22 +104,16 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable // create a jandex index from the annotated classes Indexer indexer = new Indexer(); for ( Class clazz : metadataSources.getAnnotatedClasses() ) { - InputStream stream = getClass().getClassLoader().getResourceAsStream( - clazz.getName().replace( '.', '/' ) + ".class" - ); - try { - indexer.index( stream ); - } - catch ( IOException e ) { - // Todo which exception to throw here? (HF) - throw new HibernateException( "Unable to index" ); - } + indexClass( indexer, clazz.getName().replace( '.', '/' ) + ".class" ); } - // Todo - take care of packages (HF) + // add package-info from the configured packages + for ( String packageName : metadataSources.getAnnotatedPackages() ) { + indexClass( indexer, packageName.replace( '.', '/' ) + "/package-info.class" ); + } Index index = indexer.complete(); - // process the orm.xml files + // process the xml configuration final OrmXmlParser ormParser = new OrmXmlParser( this ); List> mappings = new ArrayList>(); for ( JaxbRoot root : metadataSources.getJaxbRootList() ) { @@ -128,10 +123,29 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable } index = ormParser.parseAndUpdateIndex( mappings, index ); + // create the annotation binder and pass it the final annotation index final AnnotationBinder annotationBinder = new AnnotationBinder( this ); + annotationBinder.bindGlobalAnnotations( index ); annotationBinder.bindMappedClasses( index ); } + /** + * Adds a single class to the jandex index + * + * @param indexer the jandex indexer + * @param className the fully qualified name of the class + */ + private void indexClass(Indexer indexer, String className) { + ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + InputStream stream = classLoaderService.locateResourceStream( className ); + try { + indexer.index( stream ); + } + catch ( IOException e ) { + throw new HibernateException( "Unable to open input stream for class " + className, e ); + } + } + public BasicServiceRegistry getServiceRegistry() { return serviceRegistry; } @@ -201,5 +215,4 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable } return profile; } - } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/Foo.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/Foo.java new file mode 100644 index 0000000000..f06395ca3d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/Foo.java @@ -0,0 +1,32 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.metamodel.source.internal; + +/** + * @author Hardy Ferentschik + */ +public class Foo { +} + + diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/MetadataImplTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/MetadataImplTest.java new file mode 100644 index 0000000000..e3b9e3ec58 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/MetadataImplTest.java @@ -0,0 +1,93 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.metamodel.source.internal; + +import java.util.Iterator; + +import org.junit.Test; + +import org.hibernate.HibernateException; +import org.hibernate.metamodel.binding.FetchProfile; +import org.hibernate.metamodel.source.MetadataSources; +import org.hibernate.service.ServiceRegistryBuilder; +import org.hibernate.testing.junit4.BaseUnitTestCase; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +/** + * @author Hardy Ferentschik + */ +public class MetadataImplTest extends BaseUnitTestCase { + + @Test(expected = IllegalArgumentException.class) + public void testAddingNullClass() { + MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); + sources.addClass( null ); + sources.buildMetadata(); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddingNullPackageName() { + MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); + sources.addPackage( null ); + sources.buildMetadata(); + } + + @Test(expected = HibernateException.class) + public void testAddingNonExistingPackageName() { + MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); + sources.addPackage( "not.a.package" ); + sources.buildMetadata(); + } + + @Test + public void testAddingPackageName() { + MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); + sources.addPackage( "org.hibernate.metamodel.source.internal" ); + MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); + + assertFetchProfile( metadata ); + } + + @Test + public void testAddingPackageNameWithTrailingDot() { + MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); + sources.addPackage( "org.hibernate.metamodel.source.internal." ); + MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); + + assertFetchProfile( metadata ); + } + + private void assertFetchProfile(MetadataImpl metadata) { + Iterator profiles = metadata.getFetchProfiles().iterator(); + assertTrue( profiles.hasNext() ); + FetchProfile profile = profiles.next(); + assertEquals( "wrong profile name", "package-configured-profile", profile.getName() ); + assertFalse( profiles.hasNext() ); + } +} + + diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/package-info.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/package-info.java new file mode 100644 index 0000000000..cf82afd1f1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/internal/package-info.java @@ -0,0 +1,31 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +@FetchProfile(name = "package-configured-profile", fetchOverrides = { + @FetchProfile.FetchOverride(entity = Foo.class, association = "bar", mode = FetchMode.JOIN) +}) +package org.hibernate.metamodel.source.internal; + +import org.hibernate.annotations.FetchMode; +import org.hibernate.annotations.FetchProfile; +