HHH-6537 Adding check for @MapsId annotation to AssociationAttribute.

This commit is contained in:
Hardy Ferentschik 2011-08-05 12:32:00 +02:00
parent 21ea415f61
commit 89991f8610
6 changed files with 144 additions and 36 deletions

View File

@ -37,12 +37,15 @@ import org.jboss.jandex.DotName;
import org.hibernate.FetchMode;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.source.annotations.AnnotationBindingContext;
import org.hibernate.metamodel.source.MappingException;
import org.hibernate.metamodel.source.annotations.EnumConversionHelper;
import org.hibernate.metamodel.source.annotations.HibernateDotNames;
import org.hibernate.metamodel.source.annotations.JPADotNames;
import org.hibernate.metamodel.source.annotations.JandexHelper;
import org.hibernate.metamodel.source.annotations.attribute.type.AttributeTypeResolver;
import org.hibernate.metamodel.source.annotations.attribute.type.AttributeTypeResolverImpl;
import org.hibernate.metamodel.source.annotations.attribute.type.CompositeAttributeTypeResolver;
import org.hibernate.metamodel.source.annotations.entity.EntityBindingContext;
/**
* Represents an association attribute.
@ -60,6 +63,8 @@ public class AssociationAttribute extends MappedAttribute {
private final boolean isLazy;
private final boolean isOrphanRemoval;
private final FetchMode fetchMode;
private final boolean mapsId;
private final String referencedIdAttributeName;
private boolean isInsertable = true;
private boolean isUpdatable = true;
@ -70,7 +75,7 @@ public class AssociationAttribute extends MappedAttribute {
AttributeNature attributeNature,
String accessType,
Map<DotName, List<AnnotationInstance>> annotations,
AnnotationBindingContext context) {
EntityBindingContext context) {
return new AssociationAttribute(
name,
attributeType,
@ -86,7 +91,7 @@ public class AssociationAttribute extends MappedAttribute {
AttributeNature associationType,
String accessType,
Map<DotName, List<AnnotationInstance>> annotations,
AnnotationBindingContext context) {
EntityBindingContext context) {
super( name, javaType, accessType, annotations, context );
this.associationNature = associationType;
this.ignoreNotFound = ignoreNotFound();
@ -105,6 +110,8 @@ public class AssociationAttribute extends MappedAttribute {
this.cascadeTypes = determineCascadeTypes( associationAnnotation );
this.fetchMode = determineFetchMode();
this.referencedIdAttributeName = determineMapsId();
this.mapsId = referencedIdAttributeName != null;
}
public boolean isIgnoreNotFound() {
@ -135,6 +142,14 @@ public class AssociationAttribute extends MappedAttribute {
return fetchMode;
}
public String getReferencedIdAttributeName() {
return referencedIdAttributeName;
}
public boolean mapsId() {
return mapsId;
}
@Override
public AttributeTypeResolver getHibernateTypeResolver() {
if ( resolver == null ) {
@ -271,10 +286,31 @@ public class AssociationAttribute extends MappedAttribute {
"value",
org.hibernate.annotations.FetchMode.class
);
mode = EnumConversionHelper.annotationFetchModeToHibernateFetchMode( annotationFetchMode );
}
return mode;
}
private String determineMapsId() {
String referencedIdAttributeName;
AnnotationInstance mapsIdAnnotation = JandexHelper.getSingleAnnotation( annotations(), JPADotNames.MAPS_ID );
if ( mapsIdAnnotation == null ) {
return null;
}
if ( !( AttributeNature.MANY_TO_ONE.equals( getAssociationNature() ) || AttributeNature.MANY_TO_ONE
.equals( getAssociationNature() ) ) ) {
throw new MappingException(
"@MapsId can only be specified on a many-to-one or one-to-one associations",
getContext().getOrigin()
);
}
referencedIdAttributeName = JandexHelper.getValue( mapsIdAnnotation, "value", String.class );
return referencedIdAttributeName;
}
}

View File

@ -40,17 +40,17 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.binding.IdGenerator;
import org.hibernate.metamodel.source.MappingException;
import org.hibernate.metamodel.source.annotations.AnnotationBindingContext;
import org.hibernate.metamodel.source.annotations.EnumConversionHelper;
import org.hibernate.metamodel.source.annotations.HibernateDotNames;
import org.hibernate.metamodel.source.annotations.JPADotNames;
import org.hibernate.metamodel.source.annotations.JandexHelper;
import org.hibernate.metamodel.source.annotations.EnumConversionHelper;
import org.hibernate.metamodel.source.annotations.attribute.type.AttributeTypeResolver;
import org.hibernate.metamodel.source.annotations.attribute.type.AttributeTypeResolverImpl;
import org.hibernate.metamodel.source.annotations.attribute.type.CompositeAttributeTypeResolver;
import org.hibernate.metamodel.source.annotations.attribute.type.EnumeratedTypeResolver;
import org.hibernate.metamodel.source.annotations.attribute.type.AttributeTypeResolverImpl;
import org.hibernate.metamodel.source.annotations.attribute.type.LobTypeResolver;
import org.hibernate.metamodel.source.annotations.attribute.type.TemporalTypeResolver;
import org.hibernate.metamodel.source.annotations.entity.EntityBindingContext;
/**
* Represent a basic attribute (explicitly or implicitly mapped).
@ -96,7 +96,7 @@ public class BasicAttribute extends MappedAttribute {
Class<?> attributeType,
Map<DotName, List<AnnotationInstance>> annotations,
String accessType,
AnnotationBindingContext context) {
EntityBindingContext context) {
return new BasicAttribute( name, attributeType, accessType, annotations, context );
}
@ -104,7 +104,7 @@ public class BasicAttribute extends MappedAttribute {
Class<?> attributeType,
String accessType,
Map<DotName, List<AnnotationInstance>> annotations,
AnnotationBindingContext context) {
EntityBindingContext context) {
super( name, attributeType, accessType, annotations, context );
AnnotationInstance versionAnnotation = JandexHelper.getSingleAnnotation( annotations, JPADotNames.VERSION );

View File

@ -30,11 +30,11 @@ import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.DotName;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.source.annotations.AnnotationBindingContext;
import org.hibernate.metamodel.source.annotations.HibernateDotNames;
import org.hibernate.metamodel.source.annotations.JPADotNames;
import org.hibernate.metamodel.source.annotations.JandexHelper;
import org.hibernate.metamodel.source.annotations.attribute.type.AttributeTypeResolver;
import org.hibernate.metamodel.source.annotations.entity.EntityBindingContext;
/**
* Base class for the different types of mapped attributes
@ -82,9 +82,9 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
/**
* The binding context
*/
private final AnnotationBindingContext context;
private final EntityBindingContext context;
MappedAttribute(String name, Class<?> attributeType, String accessType, Map<DotName, List<AnnotationInstance>> annotations, AnnotationBindingContext context) {
MappedAttribute(String name, Class<?> attributeType, String accessType, Map<DotName, List<AnnotationInstance>> annotations, EntityBindingContext context) {
this.context = context;
this.annotations = annotations;
this.name = name;
@ -120,7 +120,7 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
return accessType;
}
public AnnotationBindingContext getContext() {
public EntityBindingContext getContext() {
return context;
}

View File

@ -137,7 +137,7 @@ public class ConfiguredClass {
*/
private final String customTuplizer;
private final LocalBindingContextImpl localBindingContext;
private final EntityBindingContext localBindingContext;
public ConfiguredClass(
ClassInfo classInfo,
@ -155,7 +155,7 @@ public class ConfiguredClass {
this.idAttributeMap = new TreeMap<String, BasicAttribute>();
this.associationAttributeMap = new TreeMap<String, AssociationAttribute>();
this.localBindingContext = new LocalBindingContextImpl( context, this );
this.localBindingContext = new EntityBindingContext( context, this );
collectAttributes();
attributeOverrideMap = Collections.unmodifiableMap( findAttributeOverrides() );
@ -177,7 +177,7 @@ public class ConfiguredClass {
return parent;
}
public LocalBindingContextImpl getLocalBindingContext() {
public EntityBindingContext getLocalBindingContext() {
return localBindingContext;
}

View File

@ -44,11 +44,11 @@ import org.hibernate.service.ServiceRegistry;
*
* @author Steve Ebersole
*/
public class LocalBindingContextImpl implements LocalBindingContext, AnnotationBindingContext {
public class EntityBindingContext implements LocalBindingContext, AnnotationBindingContext {
private final AnnotationBindingContext contextDelegate;
private final Origin origin;
public LocalBindingContextImpl(AnnotationBindingContext contextDelegate, ConfiguredClass source) {
public EntityBindingContext(AnnotationBindingContext contextDelegate, ConfiguredClass source) {
this.contextDelegate = contextDelegate;
this.origin = new Origin( SourceType.ANNOTATION, source.getName() );
}

View File

@ -0,0 +1,72 @@
package org.hibernate.metamodel.source.annotations.entity;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.MapsId;
import javax.persistence.OneToMany;
import org.junit.Test;
import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.source.MappingException;
import org.hibernate.service.ServiceRegistryBuilder;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
/**
* @author Hardy Ferentschik
*/
public class MapsIdTest extends BaseAnnotationBindingTestCase {
@Entity
public class Employee {
@Id
long empId;
String name;
}
@Embeddable
public class DependentId {
String name;
long empid; // corresponds to PK type of Employee
}
@Entity
public class Dependent {
@Id
// should be @EmbeddedId, but embedded id are not working atm
DependentId id;
@MapsId("empid")
@OneToMany
Employee emp; // maps the empid attribute of embedded id @ManyToOne Employee emp;
}
@Test
@Resources(annotatedClasses = DependentId.class)
public void testMapsIsOnOneToManyThrowsException() {
try {
sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() );
sources.addAnnotatedClass( DependentId.class );
sources.addAnnotatedClass( Dependent.class );
sources.addAnnotatedClass( Employee.class );
sources.buildMetadata();
fail();
}
catch ( MappingException e ) {
assertTrue(
e.getMessage()
.startsWith( "@MapsId can only be specified on a many-to-one or one-to-one associations" )
);
assertEquals(
"Wrong error origin",
"org.hibernate.metamodel.source.annotations.entity.MapsIdTest$Dependent",
e.getOrigin().getName()
);
}
}
}