HHH-7571 Starting to process @JoinTable and @CollectionTable

Moving JoinColumn processing into association attribute
Making anonymous ExplicitHibernateTypeSource implementation its own class
This commit is contained in:
Hardy Ferentschik 2012-09-06 17:50:03 +02:00
parent d661c3823d
commit ebcc59f0a1
8 changed files with 253 additions and 54 deletions

View File

@ -22,7 +22,7 @@ public class BasicPluralAttributeElementSourceImpl implements BasicPluralAttribu
@Override @Override
public ExplicitHibernateTypeSource getExplicitHibernateTypeSource() { public ExplicitHibernateTypeSource getExplicitHibernateTypeSource() {
return null; //To change body of implemented methods use File | Settings | File Templates. return new ExplicitHibernateTypeSourceImpl( associationAttribute );
} }
@Override @Override
@ -51,6 +51,7 @@ public class BasicPluralAttributeElementSourceImpl implements BasicPluralAttribu
return valueSources; return valueSources;
} }
// TODO - these values are also hard coded in the hbm version of this source implementation. Do we really need them? (HF)
@Override @Override
public boolean areValuesIncludedInInsertByDefault() { public boolean areValuesIncludedInInsertByDefault() {
return true; return true;

View File

@ -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<String, String> getParameters() {
return attribute.getHibernateTypeResolver().getExplicitHibernateTypeParameters();
}
}

View File

@ -61,17 +61,7 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab
this.nature = resolveAttributeNature(); this.nature = resolveAttributeNature();
this.keySource = new PluralAttributeKeySourceImpl( attribute ); this.keySource = new PluralAttributeKeySourceImpl( attribute );
this.elementSource = determineElementSource(); this.elementSource = determineElementSource();
this.typeSource = new ExplicitHibernateTypeSource() { this.typeSource = new ExplicitHibernateTypeSourceImpl( attribute );
@Override
public String getName() {
return attribute.getHibernateTypeResolver().getExplicitHibernateTypeName();
}
@Override
public Map<String, String> getParameters() {
return attribute.getHibernateTypeResolver().getExplicitHibernateTypeParameters();
}
};
} }
@Override @Override

View File

@ -23,6 +23,8 @@
*/ */
package org.hibernate.metamodel.internal.source.annotations.attribute; package org.hibernate.metamodel.internal.source.annotations.attribute;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -61,14 +63,12 @@ public class AssociationAttribute extends MappedAttribute {
private final boolean isOptional; private final boolean isOptional;
private final boolean isLazy; private final boolean isLazy;
private final boolean isOrphanRemoval; 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 FetchMode fetchMode;
private final FetchStyle fetchStyle; private final FetchStyle fetchStyle;
private final boolean mapsId; private final boolean mapsId;
private final String referencedIdAttributeName; private final String referencedIdAttributeName;
private final List<Column> joinColumnValues;
private boolean isInsertable = true; private final boolean definesExplicitJoinTable;
private boolean isUpdatable = true;
private AttributeTypeResolver resolver; private AttributeTypeResolver resolver;
public static AssociationAttribute createAssociationAttribute( public static AssociationAttribute createAssociationAttribute(
@ -78,11 +78,17 @@ public class AssociationAttribute extends MappedAttribute {
String accessType, String accessType,
Map<DotName, List<AnnotationInstance>> annotations, Map<DotName, List<AnnotationInstance>> annotations,
EntityBindingContext context) { EntityBindingContext context) {
return new AssociationAttribute( name, attributeType, attributeType, attributeNature, accessType, annotations, context ); return new AssociationAttribute(
name,
attributeType,
attributeType,
attributeNature,
accessType,
annotations,
context
);
} }
AssociationAttribute( AssociationAttribute(
String name, String name,
Class<?> attributeType, Class<?> attributeType,
@ -106,11 +112,14 @@ public class AssociationAttribute extends MappedAttribute {
this.isLazy = determineIsLazy( associationAnnotation ); this.isLazy = determineIsLazy( associationAnnotation );
this.isOrphanRemoval = determineOrphanRemoval( associationAnnotation ); this.isOrphanRemoval = determineOrphanRemoval( associationAnnotation );
this.cascadeTypes = determineCascadeTypes( associationAnnotation ); this.cascadeTypes = determineCascadeTypes( associationAnnotation );
this.joinColumnValues = determineJoinColumnAnnotations( annotations );
this.fetchMode = determineFetchMode(); this.fetchMode = determineFetchMode();
this.fetchStyle = determineFetchStyle(); this.fetchStyle = determineFetchStyle();
this.referencedIdAttributeName = determineMapsId(); this.referencedIdAttributeName = determineMapsId();
this.mapsId = referencedIdAttributeName != null; this.mapsId = referencedIdAttributeName != null;
this.definesExplicitJoinTable = determineExplicitJoinTable( annotations );
} }
public boolean isIgnoreNotFound() { public boolean isIgnoreNotFound() {
@ -149,6 +158,14 @@ public class AssociationAttribute extends MappedAttribute {
return mapsId; return mapsId;
} }
public List<Column> getJoinColumnValues() {
return joinColumnValues;
}
public boolean definesExplicitJoinTable() {
return definesExplicitJoinTable;
}
@Override @Override
public AttributeTypeResolver getHibernateTypeResolver() { public AttributeTypeResolver getHibernateTypeResolver() {
if ( resolver == null ) { if ( resolver == null ) {
@ -169,12 +186,12 @@ public class AssociationAttribute extends MappedAttribute {
@Override @Override
public boolean isInsertable() { public boolean isInsertable() {
return isInsertable; return true;
} }
@Override @Override
public boolean isUpdatable() { public boolean isUpdatable() {
return isUpdatable; return true;
} }
@Override @Override
@ -316,6 +333,77 @@ public class AssociationAttribute extends MappedAttribute {
} }
return JandexHelper.getValue( mapsIdAnnotation, "value", String.class ); return JandexHelper.getValue( mapsIdAnnotation, "value", String.class );
} }
private List<Column> determineJoinColumnAnnotations(Map<DotName, List<AnnotationInstance>> annotations) {
ArrayList<Column> joinColumns = new ArrayList<Column>();
// 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<AnnotationInstance> 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<DotName, List<AnnotationInstance>> 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;
}
} }

View File

@ -63,7 +63,7 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
/** /**
* The nature of the attribute * 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 * 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<MappedAttribute> {
*/ */
private List<Column> columnValues = new ArrayList<Column>(); private List<Column> columnValues = new ArrayList<Column>();
private List<Column> joinColumnValues = new ArrayList<Column>();
/** /**
* Is this property an id property (or part thereof). * Is this property an id property (or part thereof).
*/ */
@ -154,10 +152,6 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
return columnValues; return columnValues;
} }
public List<Column> getJoinColumnValues() {
return joinColumnValues;
}
public boolean isId() { public boolean isId() {
return isId; return isId;
} }
@ -250,15 +244,6 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
columnValues.add( new Column( columnAnnotation ) ); 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 // @org.hibernate.annotations.Columns
AnnotationInstance columnsAnnotation = JandexHelper.getSingleAnnotation( AnnotationInstance columnsAnnotation = JandexHelper.getSingleAnnotation(
annotations, annotations,
@ -278,20 +263,6 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
columnValues.add( new Column( annotation ) ); columnValues.add( new Column( annotation ) );
} }
} }
// @JoinColumns
AnnotationInstance joinColumnsAnnotation = JandexHelper.getSingleAnnotation(
annotations,
JPADotNames.JOIN_COLUMNS
);
if ( joinColumnsAnnotation != null ) {
List<AnnotationInstance> columnsList = Arrays.asList(
JandexHelper.getValue( joinColumnsAnnotation, "value", AnnotationInstance[].class )
);
for ( AnnotationInstance annotation : columnsList ) {
joinColumnValues.add( new Column( annotation ) );
}
}
} }
private String checkCheckAnnotation() { private String checkCheckAnnotation() {

View File

@ -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<String> strings;
public int getId() {
return id;
}
public List<String> 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<String> strings;
public int getId() {
return id;
}
public List<String> getStrings() {
return strings;
}
}
@Test(expected = MappingException.class)
@Resources(annotatedClasses = { TestEntity.class })
public void testCollectionTableAndJoinTableThrowsException() {
getEntityBinding( TestEntity.class );
}
}

View File

@ -158,7 +158,7 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase {
OtherSubclassOfSingleTableInheritance.class, OtherSubclassOfSingleTableInheritance.class,
SubclassOfSubclassOfSingleTableInheritance.class SubclassOfSubclassOfSingleTableInheritance.class
}) })
public void testRootPolymporhism() { public void testRootPolymporphism() {
EntityBinding rootEntityBinding = getEntityBinding( RootOfSingleTableInheritance.class ); EntityBinding rootEntityBinding = getEntityBinding( RootOfSingleTableInheritance.class );
EntityBinding subclassEntityBinding = getEntityBinding( SubclassOfSingleTableInheritance.class ); EntityBinding subclassEntityBinding = getEntityBinding( SubclassOfSingleTableInheritance.class );
EntityBinding otherSubclassEntityBinding = getEntityBinding( OtherSubclassOfSingleTableInheritance.class ); EntityBinding otherSubclassEntityBinding = getEntityBinding( OtherSubclassOfSingleTableInheritance.class );

View File

@ -104,7 +104,7 @@ public abstract class BaseAnnotationBindingTestCase extends BaseUnitTestCase {
} }
} }
private void createBindings() { private void createBindings() throws Throwable {
try { try {
sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() );
Resources resourcesAnnotation = origFrameworkMethod.getAnnotation( Resources.class ); Resources resourcesAnnotation = origFrameworkMethod.getAnnotation( Resources.class );
@ -127,6 +127,7 @@ public abstract class BaseAnnotationBindingTestCase extends BaseUnitTestCase {
Class<?> expected = testAnnotation.expected(); Class<?> expected = testAnnotation.expected();
if ( t.getClass().equals( expected ) ) { if ( t.getClass().equals( expected ) ) {
expectedException = true; expectedException = true;
return;
} }
} }
} }