HHH-6161 Taking care of added package names via MetadataSources.addPackage

This commit is contained in:
Hardy Ferentschik 2011-04-27 15:36:56 +02:00
parent 805191524d
commit d953449b3a
8 changed files with 222 additions and 23 deletions

View File

@ -120,11 +120,17 @@ public class MetadataSources {
/** /**
* Read package-level metadata. * 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) * @return this (for method chaining)
*/ */
public MetadataSources addPackage(String packageName) { 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 ); annotatedPackages.add( packageName );
return this; 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 * 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. * 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) * @return this (for method chaining purposes)
*/ */
public MetadataSources addClass(Class entityClass) { 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() ); LOG.debugf( "adding resource mappings from class convention : %s", entityClass.getName() );
final String mappingResourceName = entityClass.getName().replace( '.', '/' ) + ".hbm.xml"; final String mappingResourceName = entityClass.getName().replace( '.', '/' ) + ".hbm.xml";
addResource( mappingResourceName ); addResource( mappingResourceName );
@ -207,7 +216,7 @@ public class MetadataSources {
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*/ */
public MetadataSources addFile(File file) { public MetadataSources addFile(File file) {
final String name = file.getAbsolutePath(); final String name = file.getAbsolutePath();
LOG.tracef( "reading mappings from file : %s", name ); LOG.tracef( "reading mappings from file : %s", name );
final Origin origin = new Origin( SourceType.FILE, name ); final Origin origin = new Origin( SourceType.FILE, name );
try { try {
@ -319,7 +328,7 @@ public class MetadataSources {
try { try {
add( jarFile.getInputStream( zipEntry ), origin, true ); add( jarFile.getInputStream( zipEntry ), origin, true );
} }
catch (Exception e) { catch ( Exception e ) {
throw new MappingException( "could not read mapping documents", e, origin ); throw new MappingException( "could not read mapping documents", e, origin );
} }
} }
@ -329,11 +338,11 @@ public class MetadataSources {
try { try {
jarFile.close(); jarFile.close();
} }
catch (Exception ignore) { catch ( Exception ignore ) {
} }
} }
} }
catch (IOException e) { catch ( IOException e ) {
throw new MappingNotFoundException( e, origin ); throw new MappingNotFoundException( e, origin );
} }
return this; return this;
@ -345,7 +354,9 @@ public class MetadataSources {
* Assumes that any file named <tt>*.hbm.xml</tt> is a mapping document. * Assumes that any file named <tt>*.hbm.xml</tt> is a mapping document.
* *
* @param dir The directory * @param dir The directory
*
* @return this (for method chaining purposes) * @return this (for method chaining purposes)
*
* @throws org.hibernate.MappingException Indicates problems reading the jar file or * @throws org.hibernate.MappingException Indicates problems reading the jar file or
* processing the contained mapping documents. * processing the contained mapping documents.
*/ */

View File

@ -26,11 +26,11 @@ package org.hibernate.metamodel.source.annotations;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.Index; import org.jboss.jandex.Index;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.annotations.util.ConfiguredClassHierarchyBuilder;
import org.hibernate.metamodel.source.internal.MetadataImpl; import org.hibernate.metamodel.source.internal.MetadataImpl;
@ -51,6 +51,16 @@ public class AnnotationBinder {
this.metadata = metadata; 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) { public void bindMappedClasses(Index annotationIndex) {
// need to order our annotated entities into an order we can process // need to order our annotated entities into an order we can process
Set<ConfiguredClassHierarchy> hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( Set<ConfiguredClassHierarchy> hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies(
@ -79,8 +89,6 @@ public class AnnotationBinder {
// PersistentClass persistentClass = makePersistentClass( inheritanceState, superEntity ); // PersistentClass persistentClass = makePersistentClass( inheritanceState, superEntity );
// entityBinder.setInheritanceState( inheritanceState ); // entityBinder.setInheritanceState( inheritanceState );
// //
// bindQueries( clazzToProcess, mappings ); // bindQueries( clazzToProcess, mappings );

View File

@ -67,7 +67,7 @@ public class FetchProfileBinder {
bindFetchProfileAnnotations( meta, fetchProfileAnnotations ); bindFetchProfileAnnotations( meta, fetchProfileAnnotations );
} }
public static void bindFetchProfileAnnotations(MetadataImpl meta, List<AnnotationInstance> fetchProfileAnnotations) { private static void bindFetchProfileAnnotations(MetadataImpl meta, List<AnnotationInstance> fetchProfileAnnotations) {
for ( AnnotationInstance fetchProfileAnnotation : fetchProfileAnnotations ) { for ( AnnotationInstance fetchProfileAnnotation : fetchProfileAnnotations ) {
String name = fetchProfileAnnotation.value( "name" ).asString(); String name = fetchProfileAnnotation.value( "name" ).asString();
FetchProfile profile = meta.findOrCreateFetchProfile( name, MetadataSource.ANNOTATIONS ); FetchProfile profile = meta.findOrCreateFetchProfile( name, MetadataSource.ANNOTATIONS );

View File

@ -30,11 +30,13 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo; import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName; import org.jboss.jandex.DotName;
import org.jboss.jandex.Index; import org.jboss.jandex.Index;
import org.hibernate.metamodel.source.annotations.ConfiguredClassHierarchy; import org.hibernate.metamodel.source.annotations.ConfiguredClassHierarchy;
import org.hibernate.metamodel.source.annotations.JPADotNames;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.classloading.spi.ClassLoaderService; import org.hibernate.service.classloading.spi.ClassLoaderService;
@ -59,6 +61,15 @@ public class ConfiguredClassHierarchyBuilder {
Map<ClassInfo, List<ClassInfo>> processedClassInfos = new HashMap<ClassInfo, List<ClassInfo>>(); Map<ClassInfo, List<ClassInfo>> processedClassInfos = new HashMap<ClassInfo, List<ClassInfo>>();
for ( ClassInfo info : index.getKnownClasses() ) { 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 ) ) { if ( processedClassInfos.containsKey( info ) ) {
continue; continue;
} }

View File

@ -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.hbm.xml.mapping.XMLHibernateMapping;
import org.hibernate.metamodel.source.spi.MetadataImplementor; import org.hibernate.metamodel.source.spi.MetadataImplementor;
import org.hibernate.service.BasicServiceRegistry; import org.hibernate.service.BasicServiceRegistry;
import org.hibernate.service.classloading.spi.ClassLoaderService;
/** /**
* Container for configuration data while building and binding the metamodel * 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 // create a jandex index from the annotated classes
Indexer indexer = new Indexer(); Indexer indexer = new Indexer();
for ( Class<?> clazz : metadataSources.getAnnotatedClasses() ) { for ( Class<?> clazz : metadataSources.getAnnotatedClasses() ) {
InputStream stream = getClass().getClassLoader().getResourceAsStream( indexClass( indexer, clazz.getName().replace( '.', '/' ) + ".class" );
clazz.getName().replace( '.', '/' ) + ".class"
);
try {
indexer.index( stream );
}
catch ( IOException e ) {
// Todo which exception to throw here? (HF)
throw new HibernateException( "Unable to index" );
}
} }
// 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(); Index index = indexer.complete();
// process the orm.xml files // process the xml configuration
final OrmXmlParser ormParser = new OrmXmlParser( this ); final OrmXmlParser ormParser = new OrmXmlParser( this );
List<JaxbRoot<XMLEntityMappings>> mappings = new ArrayList<JaxbRoot<XMLEntityMappings>>(); List<JaxbRoot<XMLEntityMappings>> mappings = new ArrayList<JaxbRoot<XMLEntityMappings>>();
for ( JaxbRoot<?> root : metadataSources.getJaxbRootList() ) { for ( JaxbRoot<?> root : metadataSources.getJaxbRootList() ) {
@ -128,10 +123,29 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable
} }
index = ormParser.parseAndUpdateIndex( mappings, index ); index = ormParser.parseAndUpdateIndex( mappings, index );
// create the annotation binder and pass it the final annotation index
final AnnotationBinder annotationBinder = new AnnotationBinder( this ); final AnnotationBinder annotationBinder = new AnnotationBinder( this );
annotationBinder.bindGlobalAnnotations( index );
annotationBinder.bindMappedClasses( 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() { public BasicServiceRegistry getServiceRegistry() {
return serviceRegistry; return serviceRegistry;
} }
@ -201,5 +215,4 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable
} }
return profile; return profile;
} }
} }

View File

@ -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 {
}

View File

@ -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<FetchProfile> profiles = metadata.getFetchProfiles().iterator();
assertTrue( profiles.hasNext() );
FetchProfile profile = profiles.next();
assertEquals( "wrong profile name", "package-configured-profile", profile.getName() );
assertFalse( profiles.hasNext() );
}
}

View File

@ -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;