From 82ae20598bb0201434e873c0659300862810d7db Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Fri, 15 Apr 2011 15:04:46 +0200 Subject: [PATCH] HHH-6114 Implementing fetch profile parsing and binding as example for other global configurations --- .../global/FetchProfileBinder.java | 89 +++++++++++++ .../annotations/global/package-info.java | 30 +++++ .../global/FetchProfileBinderTest.java | 122 ++++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/package-info.java create mode 100644 hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinderTest.java 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 new file mode 100644 index 0000000000..a6364c93da --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java @@ -0,0 +1,89 @@ +/* + * 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.annotations.global; + +import java.util.Arrays; +import java.util.List; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.Index; + +import org.hibernate.MappingException; +import org.hibernate.annotations.FetchMode; +import org.hibernate.mapping.FetchProfile; +import org.hibernate.mapping.MetadataSource; +import org.hibernate.metamodel.source.annotations.HibernateDotNames; +import org.hibernate.metamodel.source.internal.MetadataImpl; + +/** + * Binds fetch profiles found in annotations. + * + * @author Hardy Ferentschik + */ +public class FetchProfileBinder { + /** + * Binds all {@link org.hibernate.annotations.FetchProfiles} and {@link org.hibernate.annotations.FetchProfile} \ + * annotations to the specified meta data instance. + * + * @param meta the global metadata + * @param index the annotation index repository + */ + // TODO how to handle fetch profiles defined in hbm and annotations. Which overrides which? + // TODO verify that association exists. See former VerifyFetchProfileReferenceSecondPass + public static void bindFetchProfiles(MetadataImpl meta, Index index) { + // check @FetchProfiles + List fetchProfilesAnnotations = index.getAnnotations( HibernateDotNames.FETCH_PROFILES ); + for ( AnnotationInstance fetchProfilesAnnotation : fetchProfilesAnnotations ) { + AnnotationInstance fetchProfiles[] = fetchProfilesAnnotation.value().asNestedArray(); + bindFetchProfileAnnotations( meta, Arrays.asList( fetchProfiles ) ); + } + + // check @FetchProfile + List fetchProfileAnnotations = index.getAnnotations( HibernateDotNames.FETCH_PROFILE ); + bindFetchProfileAnnotations( meta, fetchProfileAnnotations ); + } + + public static void bindFetchProfileAnnotations(MetadataImpl meta, List fetchProfileAnnotations) { + for ( AnnotationInstance fetchProfileAnnotation : fetchProfileAnnotations ) { + String name = fetchProfileAnnotation.value( "name" ).asString(); + FetchProfile profile = meta.findOrCreateFetchProfile( name, MetadataSource.ANNOTATIONS ); + + AnnotationInstance overrides[] = fetchProfileAnnotation.value( "fetchOverrides" ).asNestedArray(); + for ( AnnotationInstance overrideAnnotation : overrides ) { + FetchMode fetchMode = Enum.valueOf( FetchMode.class, overrideAnnotation.value( "mode" ).asEnum() ); + if ( !fetchMode.equals( org.hibernate.annotations.FetchMode.JOIN ) ) { + throw new MappingException( "Only FetchMode.JOIN is currently supported" ); + } + + String entityClassName = overrideAnnotation.value( "entity" ).asClass().name().toString(); + String associationName = overrideAnnotation.value( "association" ).asString(); + profile.addFetch( + entityClassName, associationName, fetchMode.toString().toLowerCase() + ); + } + } + } +} + + diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/package-info.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/package-info.java new file mode 100644 index 0000000000..2c52d4cebf --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/package-info.java @@ -0,0 +1,30 @@ +/* + * 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.annotations.global; + +/** + * This package contains binders for global configuration annotations, for example {@link javax.persistence.SequenceGenerator}, + * {@link javax.persistence.TableGenerator} or {@link org.hibernate.annotations.FetchProfile}. + * This type of annotations contains global configuration which can be bound w/o information of the mapped entities. + */ \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinderTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinderTest.java new file mode 100644 index 0000000000..ded3c2f00d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinderTest.java @@ -0,0 +1,122 @@ +package org.hibernate.metamodel.source.annotations.global; + +import java.util.Collections; +import java.util.Iterator; + +import org.jboss.jandex.Index; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.hibernate.MappingException; +import org.hibernate.annotations.FetchMode; +import org.hibernate.annotations.FetchProfile; +import org.hibernate.annotations.FetchProfiles; +import org.hibernate.metamodel.source.MetadataSources; +import org.hibernate.metamodel.source.annotations.util.JandexHelper; +import org.hibernate.metamodel.source.internal.MetadataImpl; +import org.hibernate.service.classloading.spi.ClassLoaderService; +import org.hibernate.service.internal.BasicServiceRegistryImpl; +import org.hibernate.testing.junit4.BaseUnitTestCase; + +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Hardy Ferentschik + */ +public class FetchProfileBinderTest extends BaseUnitTestCase { + + private BasicServiceRegistryImpl serviceRegistry; + private ClassLoaderService service; + private MetadataImpl meta; + + @Before + public void setUp() { + serviceRegistry = new BasicServiceRegistryImpl( Collections.emptyMap() ); + service = serviceRegistry.getService( ClassLoaderService.class ); + meta = new MetadataImpl( new MetadataSources( serviceRegistry ) ); + } + + @After + public void tearDown() { + serviceRegistry.destroy(); + } + + @Test + public void testSingleFetchProfile() { + @FetchProfile(name = "foo", fetchOverrides = { + @FetchProfile.FetchOverride(entity = Foo.class, association = "bar", mode = FetchMode.JOIN) + }) + class Foo { + } + Index index = JandexHelper.indexForClass( service, Foo.class ); + + FetchProfileBinder.bindFetchProfiles( meta, index ); + + Iterator mappedFetchProfiles = meta.getFetchProfiles().iterator(); + assertTrue( mappedFetchProfiles.hasNext() ); + org.hibernate.mapping.FetchProfile profile = mappedFetchProfiles.next(); + assertEquals( "Wrong fetch profile name", "foo", profile.getName() ); + org.hibernate.mapping.FetchProfile.Fetch fetch = profile.getFetches().iterator().next(); + assertEquals( "Wrong association name", "bar", fetch.getAssociation() ); + assertEquals( "Wrong association type", Foo.class.getName(), fetch.getEntity() ); + } + + @Test + public void testFetchProfiles() { + Index index = JandexHelper.indexForClass( service, FooBar.class ); + FetchProfileBinder.bindFetchProfiles( meta, index ); + + Iterator mappedFetchProfiles = meta.getFetchProfiles().iterator(); + assertTrue( mappedFetchProfiles.hasNext() ); + org.hibernate.mapping.FetchProfile profile = mappedFetchProfiles.next(); + assertProfiles( profile ); + + assertTrue( mappedFetchProfiles.hasNext() ); + profile = mappedFetchProfiles.next(); + assertProfiles( profile ); + } + + private void assertProfiles(org.hibernate.mapping.FetchProfile profile) { + if ( profile.getName().equals( "foobar" ) ) { + org.hibernate.mapping.FetchProfile.Fetch fetch = profile.getFetches().iterator().next(); + assertEquals( "Wrong association name", "foobar", fetch.getAssociation() ); + assertEquals( "Wrong association type", FooBar.class.getName(), fetch.getEntity() ); + } + else if ( profile.getName().equals( "fubar" ) ) { + org.hibernate.mapping.FetchProfile.Fetch fetch = profile.getFetches().iterator().next(); + assertEquals( "Wrong association name", "fubar", fetch.getAssociation() ); + assertEquals( "Wrong association type", FooBar.class.getName(), fetch.getEntity() ); + } + else { + fail( "Wrong fetch name:" + profile.getName() ); + } + } + + @Test(expected = MappingException.class) + public void testNonJoinFetchThrowsException() { + @FetchProfile(name = "foo", fetchOverrides = { + @FetchProfile.FetchOverride(entity = Foo.class, association = "bar", mode = FetchMode.SELECT) + }) + class Foo { + } + Index index = JandexHelper.indexForClass( service, Foo.class ); + + FetchProfileBinder.bindFetchProfiles( meta, index ); + } + + @FetchProfiles( { + @FetchProfile(name = "foobar", fetchOverrides = { + @FetchProfile.FetchOverride(entity = FooBar.class, association = "foobar", mode = FetchMode.JOIN) + }), + @FetchProfile(name = "fubar", fetchOverrides = { + @FetchProfile.FetchOverride(entity = FooBar.class, association = "fubar", mode = FetchMode.JOIN) + }) + }) + class FooBar { + } +} + +