From ebcc59f0a158ab77e75e0ecd3e08ed639b1a02d7 Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Thu, 6 Sep 2012 17:50:03 +0200 Subject: [PATCH] HHH-7571 Starting to process @JoinTable and @CollectionTable Moving JoinColumn processing into association attribute Making anonymous ExplicitHibernateTypeSource implementation its own class --- ...BasicPluralAttributeElementSourceImpl.java | 5 +- .../ExplicitHibernateTypeSourceImpl.java | 52 +++++++++ .../PluralAttributeSourceImpl.java | 12 +- .../attribute/AssociationAttribute.java | 106 ++++++++++++++++-- .../attribute/MappedAttribute.java | 31 +---- .../entity/ElementCollectionBindingTest.java | 96 ++++++++++++++++ .../entity/InheritanceBindingTest.java | 2 +- .../junit4/BaseAnnotationBindingTestCase.java | 3 +- 8 files changed, 253 insertions(+), 54 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/ExplicitHibernateTypeSourceImpl.java create mode 100644 hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/ElementCollectionBindingTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/BasicPluralAttributeElementSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/BasicPluralAttributeElementSourceImpl.java index fe6ef520c96a..bd1eefad9807 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/BasicPluralAttributeElementSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/BasicPluralAttributeElementSourceImpl.java @@ -22,7 +22,7 @@ public BasicPluralAttributeElementSourceImpl(AssociationAttribute associationAtt @Override public ExplicitHibernateTypeSource getExplicitHibernateTypeSource() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return new ExplicitHibernateTypeSourceImpl( associationAttribute ); } @Override @@ -42,7 +42,7 @@ else if ( MappedAttribute.Nature.ELEMENT_COLLECTION_EMBEDDABLE.equals( associati @Override public List relationalValueSources() { - List valueSources = new ArrayList( ); + List valueSources = new ArrayList(); if ( !associationAttribute.getColumnValues().isEmpty() ) { for ( Column columnValues : associationAttribute.getColumnValues() ) { valueSources.add( new ColumnSourceImpl( associationAttribute, null, columnValues ) ); @@ -51,6 +51,7 @@ public List relationalValueSources() { return valueSources; } + // TODO - these values are also hard coded in the hbm version of this source implementation. Do we really need them? (HF) @Override public boolean areValuesIncludedInInsertByDefault() { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/ExplicitHibernateTypeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/ExplicitHibernateTypeSourceImpl.java new file mode 100644 index 000000000000..e7ec9269a6b8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/ExplicitHibernateTypeSourceImpl.java @@ -0,0 +1,52 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.internal.source.annotations; + +import java.util.Map; + +import org.hibernate.metamodel.internal.source.annotations.attribute.AssociationAttribute; +import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource; + +/** + * @author Hardy Ferentschik + */ +public class ExplicitHibernateTypeSourceImpl implements ExplicitHibernateTypeSource { + private final AssociationAttribute attribute; + + public ExplicitHibernateTypeSourceImpl(AssociationAttribute attribute) { + this.attribute = attribute; + } + + @Override + public String getName() { + return attribute.getHibernateTypeResolver().getExplicitHibernateTypeName(); + } + + @Override + public Map getParameters() { + return attribute.getHibernateTypeResolver().getExplicitHibernateTypeParameters(); + } +} + + diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/PluralAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/PluralAttributeSourceImpl.java index 24ec95664e67..ff202ca03ceb 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/PluralAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/PluralAttributeSourceImpl.java @@ -61,17 +61,7 @@ public PluralAttributeSourceImpl(final PluralAssociationAttribute attribute) { this.nature = resolveAttributeNature(); this.keySource = new PluralAttributeKeySourceImpl( attribute ); this.elementSource = determineElementSource(); - this.typeSource = new ExplicitHibernateTypeSource() { - @Override - public String getName() { - return attribute.getHibernateTypeResolver().getExplicitHibernateTypeName(); - } - - @Override - public Map getParameters() { - return attribute.getHibernateTypeResolver().getExplicitHibernateTypeParameters(); - } - }; + this.typeSource = new ExplicitHibernateTypeSourceImpl( attribute ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/AssociationAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/AssociationAttribute.java index 0ac7d40d83f7..ed55d05aba62 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/AssociationAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/AssociationAttribute.java @@ -23,6 +23,8 @@ */ package org.hibernate.metamodel.internal.source.annotations.attribute; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -61,14 +63,12 @@ public class AssociationAttribute extends MappedAttribute { private final boolean isOptional; private final boolean isLazy; private final boolean isOrphanRemoval; - // todo FetchMode is currently used in the persisters. This will probably get replaced bt FetchStyle and FetchTiming private final FetchMode fetchMode; private final FetchStyle fetchStyle; private final boolean mapsId; private final String referencedIdAttributeName; - - private boolean isInsertable = true; - private boolean isUpdatable = true; + private final List joinColumnValues; + private final boolean definesExplicitJoinTable; private AttributeTypeResolver resolver; public static AssociationAttribute createAssociationAttribute( @@ -78,11 +78,17 @@ public static AssociationAttribute createAssociationAttribute( String accessType, Map> annotations, EntityBindingContext context) { - return new AssociationAttribute( name, attributeType, attributeType, attributeNature, accessType, annotations, context ); + return new AssociationAttribute( + name, + attributeType, + attributeType, + attributeNature, + accessType, + annotations, + context + ); } - - AssociationAttribute( String name, Class attributeType, @@ -106,11 +112,14 @@ public static AssociationAttribute createAssociationAttribute( this.isLazy = determineIsLazy( associationAnnotation ); this.isOrphanRemoval = determineOrphanRemoval( associationAnnotation ); this.cascadeTypes = determineCascadeTypes( associationAnnotation ); + this.joinColumnValues = determineJoinColumnAnnotations( annotations ); this.fetchMode = determineFetchMode(); this.fetchStyle = determineFetchStyle(); this.referencedIdAttributeName = determineMapsId(); this.mapsId = referencedIdAttributeName != null; + + this.definesExplicitJoinTable = determineExplicitJoinTable( annotations ); } public boolean isIgnoreNotFound() { @@ -149,6 +158,14 @@ public boolean mapsId() { return mapsId; } + public List getJoinColumnValues() { + return joinColumnValues; + } + + public boolean definesExplicitJoinTable() { + return definesExplicitJoinTable; + } + @Override public AttributeTypeResolver getHibernateTypeResolver() { if ( resolver == null ) { @@ -169,12 +186,12 @@ public boolean isOptional() { @Override public boolean isInsertable() { - return isInsertable; + return true; } @Override public boolean isUpdatable() { - return isUpdatable; + return true; } @Override @@ -316,6 +333,77 @@ private String determineMapsId() { } return JandexHelper.getValue( mapsIdAnnotation, "value", String.class ); } + + private List determineJoinColumnAnnotations(Map> annotations) { + ArrayList joinColumns = new ArrayList(); + + // single @JoinColumn + AnnotationInstance joinColumnAnnotation = JandexHelper.getSingleAnnotation( + annotations, + JPADotNames.JOIN_COLUMN + ); + if ( joinColumnAnnotation != null ) { + joinColumns.add( new Column( joinColumnAnnotation ) ); + } + + // @JoinColumns + AnnotationInstance joinColumnsAnnotation = JandexHelper.getSingleAnnotation( + annotations, + JPADotNames.JOIN_COLUMNS + ); + if ( joinColumnsAnnotation != null ) { + List columnsList = Arrays.asList( + JandexHelper.getValue( joinColumnsAnnotation, "value", AnnotationInstance[].class ) + ); + for ( AnnotationInstance annotation : columnsList ) { + joinColumns.add( new Column( annotation ) ); + } + } + joinColumns.trimToSize(); + return joinColumns; + } + + private boolean determineExplicitJoinTable(Map> annotations) { + AnnotationInstance collectionTableAnnotation = JandexHelper.getSingleAnnotation( + annotations, + JPADotNames.COLLECTION_TABLE + ); + + AnnotationInstance joinTableAnnotation = JandexHelper.getSingleAnnotation( + annotations, + JPADotNames.JOIN_TABLE + ); + + // sanity checks + if ( collectionTableAnnotation != null && joinTableAnnotation != null ) { + throw new MappingException( + "@CollectionTable and JoinTable specified on the same attribute", + getContext().getOrigin() + ); + } + + if ( collectionTableAnnotation != null ) { + if ( JandexHelper.getSingleAnnotation( annotations, JPADotNames.ELEMENT_COLLECTION ) == null ) { + throw new MappingException( + "@CollectionTable annotation without a @ElementCollection", + getContext().getOrigin() + ); + } + } + + if ( joinTableAnnotation != null ) { + if ( JandexHelper.getSingleAnnotation( annotations, JPADotNames.ONE_TO_ONE ) == null + && JandexHelper.getSingleAnnotation( annotations, JPADotNames.ONE_TO_MANY ) == null + && JandexHelper.getSingleAnnotation( annotations, JPADotNames.MANY_TO_MANY ) == null ) { + throw new MappingException( + "@JoinTable annotation without an association", + getContext().getOrigin() + ); + } + } + + return collectionTableAnnotation != null || joinTableAnnotation != null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/MappedAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/MappedAttribute.java index 5ebc0ff40f9a..d8ac60cf4c33 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/MappedAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/MappedAttribute.java @@ -63,7 +63,7 @@ public abstract class MappedAttribute implements Comparable { /** * The nature of the attribute */ - Nature attributeNature; + private final Nature attributeNature; /** * The access type for this property. At the moment this is either 'field' or 'property', but Hibernate @@ -77,8 +77,6 @@ public abstract class MappedAttribute implements Comparable { */ private List columnValues = new ArrayList(); - private List joinColumnValues = new ArrayList(); - /** * Is this property an id property (or part thereof). */ @@ -154,10 +152,6 @@ public List getColumnValues() { return columnValues; } - public List getJoinColumnValues() { - return joinColumnValues; - } - public boolean isId() { return isId; } @@ -250,15 +244,6 @@ private void checkColumnAnnotations(Map> annot columnValues.add( new Column( columnAnnotation ) ); } - // single @JoinColumn - AnnotationInstance joinColumnAnnotation = JandexHelper.getSingleAnnotation( - annotations, - JPADotNames.JOIN_COLUMN - ); - if ( joinColumnAnnotation != null ) { - joinColumnValues.add( new Column( joinColumnAnnotation ) ); - } - // @org.hibernate.annotations.Columns AnnotationInstance columnsAnnotation = JandexHelper.getSingleAnnotation( annotations, @@ -278,20 +263,6 @@ private void checkColumnAnnotations(Map> annot columnValues.add( new Column( annotation ) ); } } - - // @JoinColumns - AnnotationInstance joinColumnsAnnotation = JandexHelper.getSingleAnnotation( - annotations, - JPADotNames.JOIN_COLUMNS - ); - if ( joinColumnsAnnotation != null ) { - List columnsList = Arrays.asList( - JandexHelper.getValue( joinColumnsAnnotation, "value", AnnotationInstance[].class ) - ); - for ( AnnotationInstance annotation : columnsList ) { - joinColumnValues.add( new Column( annotation ) ); - } - } } private String checkCheckAnnotation() { diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/ElementCollectionBindingTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/ElementCollectionBindingTest.java new file mode 100644 index 000000000000..7680296ae18d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/ElementCollectionBindingTest.java @@ -0,0 +1,96 @@ +/* + * 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.internal.source.annotations.entity; + +import java.util.List; +import javax.persistence.CollectionTable; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinTable; + +import org.junit.Test; + +import org.hibernate.metamodel.spi.source.MappingException; +import org.hibernate.testing.junit4.BaseAnnotationBindingTestCase; +import org.hibernate.testing.junit4.Resources; + +/** + * Tests for different types of @ElementCollection mappings. + * + * @author Hardy Ferentschik + */ + +public class ElementCollectionBindingTest extends BaseAnnotationBindingTestCase { + @Entity + class TestEntity { + @Id + private int id; + + @ElementCollection + @JoinTable + private List strings; + + public int getId() { + return id; + } + + public List getStrings() { + return strings; + } + } + + @Test(expected = MappingException.class) + @Resources(annotatedClasses = { TestEntity.class }) + public void testElementCollectionWithJoinTableThrowsException() { + getEntityBinding( TestEntity.class ); + } + + @Entity + class TestEntity2 { + @Id + private int id; + + @ElementCollection + @JoinTable + @CollectionTable + private List strings; + + public int getId() { + return id; + } + + public List getStrings() { + return strings; + } + } + + @Test(expected = MappingException.class) + @Resources(annotatedClasses = { TestEntity.class }) + public void testCollectionTableAndJoinTableThrowsException() { + getEntityBinding( TestEntity.class ); + } +} + + diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/InheritanceBindingTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/InheritanceBindingTest.java index 7e104a2b6ea8..2305f4d554f4 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/InheritanceBindingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/InheritanceBindingTest.java @@ -158,7 +158,7 @@ public void testNoPolymorphism() { OtherSubclassOfSingleTableInheritance.class, SubclassOfSubclassOfSingleTableInheritance.class }) - public void testRootPolymporhism() { + public void testRootPolymporphism() { EntityBinding rootEntityBinding = getEntityBinding( RootOfSingleTableInheritance.class ); EntityBinding subclassEntityBinding = getEntityBinding( SubclassOfSingleTableInheritance.class ); EntityBinding otherSubclassEntityBinding = getEntityBinding( OtherSubclassOfSingleTableInheritance.class ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseAnnotationBindingTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseAnnotationBindingTestCase.java index a527d5659f33..53e049fc0fbd 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseAnnotationBindingTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseAnnotationBindingTestCase.java @@ -104,7 +104,7 @@ public void evaluate() throws Throwable { } } - private void createBindings() { + private void createBindings() throws Throwable { try { sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); Resources resourcesAnnotation = origFrameworkMethod.getAnnotation( Resources.class ); @@ -127,6 +127,7 @@ private void createBindings() { Class expected = testAnnotation.expected(); if ( t.getClass().equals( expected ) ) { expectedException = true; + return; } } }