HHH-6537 Adding check for @MapsId annotation to AssociationAttribute.
This commit is contained in:
parent
21ea415f61
commit
89991f8610
|
@ -37,12 +37,15 @@ import org.jboss.jandex.DotName;
|
||||||
import org.hibernate.FetchMode;
|
import org.hibernate.FetchMode;
|
||||||
import org.hibernate.annotations.NotFoundAction;
|
import org.hibernate.annotations.NotFoundAction;
|
||||||
import org.hibernate.mapping.PropertyGeneration;
|
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.HibernateDotNames;
|
||||||
|
import org.hibernate.metamodel.source.annotations.JPADotNames;
|
||||||
import org.hibernate.metamodel.source.annotations.JandexHelper;
|
import org.hibernate.metamodel.source.annotations.JandexHelper;
|
||||||
import org.hibernate.metamodel.source.annotations.attribute.type.AttributeTypeResolver;
|
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.AttributeTypeResolverImpl;
|
||||||
import org.hibernate.metamodel.source.annotations.attribute.type.CompositeAttributeTypeResolver;
|
import org.hibernate.metamodel.source.annotations.attribute.type.CompositeAttributeTypeResolver;
|
||||||
|
import org.hibernate.metamodel.source.annotations.entity.EntityBindingContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an association attribute.
|
* Represents an association attribute.
|
||||||
|
@ -60,6 +63,8 @@ public class AssociationAttribute extends MappedAttribute {
|
||||||
private final boolean isLazy;
|
private final boolean isLazy;
|
||||||
private final boolean isOrphanRemoval;
|
private final boolean isOrphanRemoval;
|
||||||
private final FetchMode fetchMode;
|
private final FetchMode fetchMode;
|
||||||
|
private final boolean mapsId;
|
||||||
|
private final String referencedIdAttributeName;
|
||||||
|
|
||||||
private boolean isInsertable = true;
|
private boolean isInsertable = true;
|
||||||
private boolean isUpdatable = true;
|
private boolean isUpdatable = true;
|
||||||
|
@ -70,7 +75,7 @@ public class AssociationAttribute extends MappedAttribute {
|
||||||
AttributeNature attributeNature,
|
AttributeNature attributeNature,
|
||||||
String accessType,
|
String accessType,
|
||||||
Map<DotName, List<AnnotationInstance>> annotations,
|
Map<DotName, List<AnnotationInstance>> annotations,
|
||||||
AnnotationBindingContext context) {
|
EntityBindingContext context) {
|
||||||
return new AssociationAttribute(
|
return new AssociationAttribute(
|
||||||
name,
|
name,
|
||||||
attributeType,
|
attributeType,
|
||||||
|
@ -86,7 +91,7 @@ public class AssociationAttribute extends MappedAttribute {
|
||||||
AttributeNature associationType,
|
AttributeNature associationType,
|
||||||
String accessType,
|
String accessType,
|
||||||
Map<DotName, List<AnnotationInstance>> annotations,
|
Map<DotName, List<AnnotationInstance>> annotations,
|
||||||
AnnotationBindingContext context) {
|
EntityBindingContext context) {
|
||||||
super( name, javaType, accessType, annotations, context );
|
super( name, javaType, accessType, annotations, context );
|
||||||
this.associationNature = associationType;
|
this.associationNature = associationType;
|
||||||
this.ignoreNotFound = ignoreNotFound();
|
this.ignoreNotFound = ignoreNotFound();
|
||||||
|
@ -105,6 +110,8 @@ public class AssociationAttribute extends MappedAttribute {
|
||||||
this.cascadeTypes = determineCascadeTypes( associationAnnotation );
|
this.cascadeTypes = determineCascadeTypes( associationAnnotation );
|
||||||
|
|
||||||
this.fetchMode = determineFetchMode();
|
this.fetchMode = determineFetchMode();
|
||||||
|
this.referencedIdAttributeName = determineMapsId();
|
||||||
|
this.mapsId = referencedIdAttributeName != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIgnoreNotFound() {
|
public boolean isIgnoreNotFound() {
|
||||||
|
@ -135,6 +142,14 @@ public class AssociationAttribute extends MappedAttribute {
|
||||||
return fetchMode;
|
return fetchMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getReferencedIdAttributeName() {
|
||||||
|
return referencedIdAttributeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mapsId() {
|
||||||
|
return mapsId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AttributeTypeResolver getHibernateTypeResolver() {
|
public AttributeTypeResolver getHibernateTypeResolver() {
|
||||||
if ( resolver == null ) {
|
if ( resolver == null ) {
|
||||||
|
@ -271,10 +286,31 @@ public class AssociationAttribute extends MappedAttribute {
|
||||||
"value",
|
"value",
|
||||||
org.hibernate.annotations.FetchMode.class
|
org.hibernate.annotations.FetchMode.class
|
||||||
);
|
);
|
||||||
|
mode = EnumConversionHelper.annotationFetchModeToHibernateFetchMode( annotationFetchMode );
|
||||||
}
|
}
|
||||||
|
|
||||||
return mode;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,17 +40,17 @@ import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.mapping.PropertyGeneration;
|
import org.hibernate.mapping.PropertyGeneration;
|
||||||
import org.hibernate.metamodel.binding.IdGenerator;
|
import org.hibernate.metamodel.binding.IdGenerator;
|
||||||
import org.hibernate.metamodel.source.MappingException;
|
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.HibernateDotNames;
|
||||||
import org.hibernate.metamodel.source.annotations.JPADotNames;
|
import org.hibernate.metamodel.source.annotations.JPADotNames;
|
||||||
import org.hibernate.metamodel.source.annotations.JandexHelper;
|
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.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.CompositeAttributeTypeResolver;
|
||||||
import org.hibernate.metamodel.source.annotations.attribute.type.EnumeratedTypeResolver;
|
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.LobTypeResolver;
|
||||||
import org.hibernate.metamodel.source.annotations.attribute.type.TemporalTypeResolver;
|
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).
|
* Represent a basic attribute (explicitly or implicitly mapped).
|
||||||
|
@ -90,13 +90,13 @@ public class BasicAttribute extends MappedAttribute {
|
||||||
private final String customWriteFragment;
|
private final String customWriteFragment;
|
||||||
private final String customReadFragment;
|
private final String customReadFragment;
|
||||||
private final String checkCondition;
|
private final String checkCondition;
|
||||||
private AttributeTypeResolver resolver;
|
private AttributeTypeResolver resolver;
|
||||||
|
|
||||||
public static BasicAttribute createSimpleAttribute(String name,
|
public static BasicAttribute createSimpleAttribute(String name,
|
||||||
Class<?> attributeType,
|
Class<?> attributeType,
|
||||||
Map<DotName, List<AnnotationInstance>> annotations,
|
Map<DotName, List<AnnotationInstance>> annotations,
|
||||||
String accessType,
|
String accessType,
|
||||||
AnnotationBindingContext context) {
|
EntityBindingContext context) {
|
||||||
return new BasicAttribute( name, attributeType, accessType, annotations, context );
|
return new BasicAttribute( name, attributeType, accessType, annotations, context );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ public class BasicAttribute extends MappedAttribute {
|
||||||
Class<?> attributeType,
|
Class<?> attributeType,
|
||||||
String accessType,
|
String accessType,
|
||||||
Map<DotName, List<AnnotationInstance>> annotations,
|
Map<DotName, List<AnnotationInstance>> annotations,
|
||||||
AnnotationBindingContext context) {
|
EntityBindingContext context) {
|
||||||
super( name, attributeType, accessType, annotations, context );
|
super( name, attributeType, accessType, annotations, context );
|
||||||
|
|
||||||
AnnotationInstance versionAnnotation = JandexHelper.getSingleAnnotation( annotations, JPADotNames.VERSION );
|
AnnotationInstance versionAnnotation = JandexHelper.getSingleAnnotation( annotations, JPADotNames.VERSION );
|
||||||
|
@ -303,25 +303,25 @@ public class BasicAttribute extends MappedAttribute {
|
||||||
return generator;
|
return generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AttributeTypeResolver getHibernateTypeResolver() {
|
public AttributeTypeResolver getHibernateTypeResolver() {
|
||||||
if ( resolver == null ) {
|
if ( resolver == null ) {
|
||||||
resolver = getDefaultHibernateTypeResolver();
|
resolver = getDefaultHibernateTypeResolver();
|
||||||
}
|
}
|
||||||
return resolver;
|
return resolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AttributeTypeResolver getDefaultHibernateTypeResolver() {
|
private AttributeTypeResolver getDefaultHibernateTypeResolver() {
|
||||||
CompositeAttributeTypeResolver resolver = new CompositeAttributeTypeResolver(
|
CompositeAttributeTypeResolver resolver = new CompositeAttributeTypeResolver(
|
||||||
new AttributeTypeResolverImpl(
|
new AttributeTypeResolverImpl(
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
resolver.addHibernateTypeResolver( new TemporalTypeResolver( this ) );
|
resolver.addHibernateTypeResolver( new TemporalTypeResolver( this ) );
|
||||||
resolver.addHibernateTypeResolver( new LobTypeResolver( this ) );
|
resolver.addHibernateTypeResolver( new LobTypeResolver( this ) );
|
||||||
resolver.addHibernateTypeResolver( new EnumeratedTypeResolver( this ) );
|
resolver.addHibernateTypeResolver( new EnumeratedTypeResolver( this ) );
|
||||||
return resolver;
|
return resolver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,11 @@ import org.jboss.jandex.AnnotationInstance;
|
||||||
import org.jboss.jandex.DotName;
|
import org.jboss.jandex.DotName;
|
||||||
|
|
||||||
import org.hibernate.mapping.PropertyGeneration;
|
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.HibernateDotNames;
|
||||||
import org.hibernate.metamodel.source.annotations.JPADotNames;
|
import org.hibernate.metamodel.source.annotations.JPADotNames;
|
||||||
import org.hibernate.metamodel.source.annotations.JandexHelper;
|
import org.hibernate.metamodel.source.annotations.JandexHelper;
|
||||||
import org.hibernate.metamodel.source.annotations.attribute.type.AttributeTypeResolver;
|
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
|
* Base class for the different types of mapped attributes
|
||||||
|
@ -82,9 +82,9 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
|
||||||
/**
|
/**
|
||||||
* The binding context
|
* 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.context = context;
|
||||||
this.annotations = annotations;
|
this.annotations = annotations;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -120,7 +120,7 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
|
||||||
return accessType;
|
return accessType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnnotationBindingContext getContext() {
|
public EntityBindingContext getContext() {
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ public class ConfiguredClass {
|
||||||
*/
|
*/
|
||||||
private final String customTuplizer;
|
private final String customTuplizer;
|
||||||
|
|
||||||
private final LocalBindingContextImpl localBindingContext;
|
private final EntityBindingContext localBindingContext;
|
||||||
|
|
||||||
public ConfiguredClass(
|
public ConfiguredClass(
|
||||||
ClassInfo classInfo,
|
ClassInfo classInfo,
|
||||||
|
@ -155,7 +155,7 @@ public class ConfiguredClass {
|
||||||
this.idAttributeMap = new TreeMap<String, BasicAttribute>();
|
this.idAttributeMap = new TreeMap<String, BasicAttribute>();
|
||||||
this.associationAttributeMap = new TreeMap<String, AssociationAttribute>();
|
this.associationAttributeMap = new TreeMap<String, AssociationAttribute>();
|
||||||
|
|
||||||
this.localBindingContext = new LocalBindingContextImpl( context, this );
|
this.localBindingContext = new EntityBindingContext( context, this );
|
||||||
|
|
||||||
collectAttributes();
|
collectAttributes();
|
||||||
attributeOverrideMap = Collections.unmodifiableMap( findAttributeOverrides() );
|
attributeOverrideMap = Collections.unmodifiableMap( findAttributeOverrides() );
|
||||||
|
@ -177,7 +177,7 @@ public class ConfiguredClass {
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalBindingContextImpl getLocalBindingContext() {
|
public EntityBindingContext getLocalBindingContext() {
|
||||||
return localBindingContext;
|
return localBindingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,11 +44,11 @@ import org.hibernate.service.ServiceRegistry;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class LocalBindingContextImpl implements LocalBindingContext, AnnotationBindingContext {
|
public class EntityBindingContext implements LocalBindingContext, AnnotationBindingContext {
|
||||||
private final AnnotationBindingContext contextDelegate;
|
private final AnnotationBindingContext contextDelegate;
|
||||||
private final Origin origin;
|
private final Origin origin;
|
||||||
|
|
||||||
public LocalBindingContextImpl(AnnotationBindingContext contextDelegate, ConfiguredClass source) {
|
public EntityBindingContext(AnnotationBindingContext contextDelegate, ConfiguredClass source) {
|
||||||
this.contextDelegate = contextDelegate;
|
this.contextDelegate = contextDelegate;
|
||||||
this.origin = new Origin( SourceType.ANNOTATION, source.getName() );
|
this.origin = new Origin( SourceType.ANNOTATION, source.getName() );
|
||||||
}
|
}
|
|
@ -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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue