HHH-6114 Starting to bind id attributes
This commit is contained in:
parent
dd9ccddc6e
commit
da028ee137
|
@ -29,13 +29,19 @@ import org.hibernate.EntityMode;
|
|||
* Models the notion of an entity
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class Entity extends AbstractAttributeContainer {
|
||||
private final PojoEntitySpecifics pojoEntitySpecifics = new PojoEntitySpecifics();
|
||||
private final Dom4jEntitySpecifics dom4jEntitySpecifics = new Dom4jEntitySpecifics();
|
||||
private final MapEntitySpecifics mapEntitySpecifics = new MapEntitySpecifics();
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for the entity
|
||||
*
|
||||
* @param name the name of the entity
|
||||
* @param superType the super type for this entity. If there is not super type {@code null} needs to be passed.
|
||||
*/
|
||||
public Entity(String name, Hierarchical superType) {
|
||||
super( name, superType );
|
||||
}
|
||||
|
@ -61,6 +67,7 @@ public class Entity extends AbstractAttributeContainer {
|
|||
|
||||
public static interface EntityModeEntitySpecifics {
|
||||
public EntityMode getEntityMode();
|
||||
|
||||
public String getTuplizerClassName();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,14 +26,12 @@ package org.hibernate.metamodel.source.annotations;
|
|||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.Index;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.hibernate.metamodel.source.annotations.util.ConfiguredClassHierarchyBuilder;
|
||||
import org.hibernate.metamodel.source.annotations.util.JandexHelper;
|
||||
import org.hibernate.metamodel.source.internal.MetadataImpl;
|
||||
|
||||
/**
|
||||
|
@ -70,34 +68,9 @@ public class AnnotationBinder {
|
|||
}
|
||||
|
||||
public void bindEntity(ConfiguredClass entity) {
|
||||
ClassInfo classInfo = entity.getClassInfo();
|
||||
log.info( "Binding entity from annotated class: {}", entity.getName() );
|
||||
EntityBinder entityBinder = new EntityBinder( metadata, entity );
|
||||
|
||||
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
|
||||
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.ENTITY );
|
||||
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation(
|
||||
classInfo, JPADotNames.MAPPED_SUPER_CLASS
|
||||
);
|
||||
AnnotationInstance hibernateEntityAnnotation = JandexHelper.getSingleAnnotation(
|
||||
classInfo, HibernateDotNames.ENTITY
|
||||
);
|
||||
|
||||
|
||||
// //TODO: be more strict with secondarytable allowance (not for ids, not for secondary table join columns etc)
|
||||
// InheritanceState inheritanceState = inheritanceStatePerClass.get( clazzToProcess );
|
||||
// AnnotatedClassType classType = mappings.getClassType( clazzToProcess );
|
||||
//
|
||||
// //Queries declared in MappedSuperclass should be usable in Subclasses
|
||||
// if ( AnnotatedClassType.EMBEDDABLE_SUPERCLASS.equals( classType ) ) {
|
||||
// bindQueries( clazzToProcess, mappings );
|
||||
// bindTypeDefs( clazzToProcess, mappings );
|
||||
// bindFilterDefs( clazzToProcess, mappings );
|
||||
// }
|
||||
//
|
||||
// if ( !isEntityClassType( clazzToProcess, classType ) ) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
log.info( "Binding entity from annotated class: {}", classInfo.name() );
|
||||
//
|
||||
// PersistentClass superEntity = getSuperEntity(
|
||||
// clazzToProcess, inheritanceStatePerClass, mappings, inheritanceState
|
||||
|
@ -106,9 +79,8 @@ public class AnnotationBinder {
|
|||
// PersistentClass persistentClass = makePersistentClass( inheritanceState, superEntity );
|
||||
|
||||
|
||||
EntityBinder entityBinder = new EntityBinder(
|
||||
metadata, classInfo, jpaEntityAnnotation, hibernateEntityAnnotation
|
||||
);
|
||||
|
||||
|
||||
// entityBinder.setInheritanceState( inheritanceState );
|
||||
//
|
||||
// bindQueries( clazzToProcess, mappings );
|
||||
|
|
|
@ -52,42 +52,47 @@ import org.hibernate.service.classloading.spi.ClassLoaderService;
|
|||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class ConfiguredClass {
|
||||
private final ConfiguredClass parent;
|
||||
private final ClassInfo classInfo;
|
||||
private final Class<?> clazz;
|
||||
private final boolean isRoot;
|
||||
private final AccessType classAccessType;
|
||||
private final ConfiguredClassHierarchy hierarchy;
|
||||
private final AccessType hierarchyAccessType;
|
||||
private final boolean isMappedSuperClass;
|
||||
private final List<MappedProperty> mappedProperties;
|
||||
|
||||
public ConfiguredClass(ClassInfo info, ConfiguredClassHierarchy hierarchy, ServiceRegistry serviceRegistry) {
|
||||
public ConfiguredClass(ClassInfo info, ConfiguredClass parent, AccessType hierarchyAccessType, ServiceRegistry serviceRegistry) {
|
||||
this.classInfo = info;
|
||||
this.hierarchy = hierarchy;
|
||||
this.parent = parent;
|
||||
this.isRoot = parent == null;
|
||||
this.hierarchyAccessType = hierarchyAccessType;
|
||||
|
||||
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
|
||||
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.ENTITY );
|
||||
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation(
|
||||
classInfo, JPADotNames.MAPPED_SUPER_CLASS
|
||||
);
|
||||
|
||||
if ( jpaEntityAnnotation != null && mappedSuperClassAnnotation != null ) {
|
||||
throw new AnnotationException(
|
||||
"An entity cannot be annotated with both @Entity and @MappedSuperclass: "
|
||||
+ classInfo.name().toString()
|
||||
);
|
||||
}
|
||||
AnnotationInstance mappedSuperClassAnnotation = assertNotEntityAndMAppedSuperClass();
|
||||
|
||||
this.clazz = serviceRegistry.getService( ClassLoaderService.class ).classForName( info.toString() );
|
||||
isMappedSuperClass = mappedSuperClassAnnotation != null;
|
||||
classAccessType = determineClassAccessType( hierarchy.getDefaultAccessType() );
|
||||
classAccessType = determineClassAccessType();
|
||||
mappedProperties = collectMappedProperties();
|
||||
// make sure the properties are ordered by property name
|
||||
Collections.sort( mappedProperties );
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return clazz.getName();
|
||||
}
|
||||
|
||||
public ClassInfo getClassInfo() {
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
public ConfiguredClass getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public boolean isRoot() {
|
||||
return isRoot;
|
||||
}
|
||||
|
||||
public boolean isMappedSuperClass() {
|
||||
return isMappedSuperClass;
|
||||
}
|
||||
|
@ -101,7 +106,7 @@ public class ConfiguredClass {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
private AccessType determineClassAccessType(AccessType hierarchyAccessType) {
|
||||
private AccessType determineClassAccessType() {
|
||||
// default to the hierarchy access type to start with
|
||||
AccessType accessType = hierarchyAccessType;
|
||||
|
||||
|
@ -231,6 +236,22 @@ public class ConfiguredClass {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AnnotationInstance assertNotEntityAndMAppedSuperClass() {
|
||||
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
|
||||
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.ENTITY );
|
||||
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation(
|
||||
classInfo, JPADotNames.MAPPED_SUPER_CLASS
|
||||
);
|
||||
|
||||
if ( jpaEntityAnnotation != null && mappedSuperClassAnnotation != null ) {
|
||||
throw new AnnotationException(
|
||||
"An entity cannot be annotated with both @Entity and @MappedSuperclass: "
|
||||
+ classInfo.name().toString()
|
||||
);
|
||||
}
|
||||
return mappedSuperClassAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -57,8 +57,11 @@ public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
|
|||
inheritanceType = determineInheritanceType( classes );
|
||||
|
||||
configuredClasses = new ArrayList<ConfiguredClass>();
|
||||
ConfiguredClass parent = null;
|
||||
for ( ClassInfo info : classes ) {
|
||||
configuredClasses.add( new ConfiguredClass( info, this, serviceRegistry ) );
|
||||
ConfiguredClass configuredClass = new ConfiguredClass( info, parent, defaultAccessType, serviceRegistry );
|
||||
configuredClasses.add( configuredClass );
|
||||
parent = configuredClass;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,30 +23,89 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.source.annotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.metamodel.binding.EntityBinding;
|
||||
import org.hibernate.metamodel.binding.SimpleAttributeBinding;
|
||||
import org.hibernate.metamodel.domain.Entity;
|
||||
import org.hibernate.metamodel.domain.Hierarchical;
|
||||
import org.hibernate.metamodel.source.annotations.util.JandexHelper;
|
||||
import org.hibernate.metamodel.source.internal.MetadataImpl;
|
||||
|
||||
/**
|
||||
* Creates the domain and relational metamodel for a configured class and binds them together.
|
||||
*
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class EntityBinder {
|
||||
private final ClassInfo classToBind;
|
||||
private final ConfiguredClass entity;
|
||||
private final MetadataImpl meta;
|
||||
|
||||
public EntityBinder(MetadataImpl metadata, ClassInfo classInfo, AnnotationInstance jpaEntityAnnotation, AnnotationInstance hibernateEntityAnnotation) {
|
||||
this.classToBind = classInfo;
|
||||
public EntityBinder(MetadataImpl metadata, ConfiguredClass configuredClass) {
|
||||
this.entity = configuredClass;
|
||||
this.meta = metadata;
|
||||
EntityBinding entityBinding = new EntityBinding();
|
||||
bindJpaAnnotation( jpaEntityAnnotation, entityBinding );
|
||||
bindHibernateAnnotation( hibernateEntityAnnotation, entityBinding );
|
||||
metadata.addEntity( entityBinding );
|
||||
bindJpaEntityAnnotation( entityBinding );
|
||||
// we also have to take care of an optional Hibernate specific @Id
|
||||
bindHibernateEntityAnnotation( entityBinding );
|
||||
if ( configuredClass.isRoot() ) {
|
||||
bindId( entityBinding );
|
||||
}
|
||||
meta.addEntity( entityBinding );
|
||||
}
|
||||
|
||||
private void bindHibernateAnnotation(AnnotationInstance annotation, EntityBinding entityBinding) {
|
||||
private void bindId(EntityBinding entityBinding) {
|
||||
switch ( determineIdType() ) {
|
||||
case SIMPLE: {
|
||||
bindSingleIdAnnotation( entityBinding );
|
||||
break;
|
||||
}
|
||||
case COMPOSED: {
|
||||
// todo
|
||||
break;
|
||||
}
|
||||
case EMBEDDED: {
|
||||
// todo
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bindJpaEntityAnnotation(EntityBinding entityBinding) {
|
||||
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation(
|
||||
entity.getClassInfo(), JPADotNames.ENTITY
|
||||
);
|
||||
String name;
|
||||
if ( jpaEntityAnnotation.value( "name" ) == null ) {
|
||||
name = StringHelper.unqualify( entity.getName() );
|
||||
}
|
||||
else {
|
||||
name = jpaEntityAnnotation.value( "name" ).asString();
|
||||
}
|
||||
entityBinding.setEntity( new Entity( name, getSuperType() ) );
|
||||
}
|
||||
|
||||
private void bindSingleIdAnnotation(EntityBinding entityBinding) {
|
||||
AnnotationInstance idAnnotation = JandexHelper.getSingleAnnotation(
|
||||
entity.getClassInfo(), JPADotNames.ID
|
||||
);
|
||||
|
||||
String idName = JandexHelper.getPropertyName( idAnnotation.target() );
|
||||
entityBinding.getEntity().getOrCreateSingularAttribute( idName );
|
||||
SimpleAttributeBinding idBinding = entityBinding.makeSimplePrimaryKeyAttributeBinding( idName );
|
||||
}
|
||||
|
||||
private void bindHibernateEntityAnnotation(EntityBinding entityBinding) {
|
||||
AnnotationInstance hibernateEntityAnnotation = JandexHelper.getSingleAnnotation(
|
||||
entity.getClassInfo(), HibernateDotNames.ENTITY
|
||||
);
|
||||
// if ( hibAnn != null ) {
|
||||
// dynamicInsert = hibAnn.dynamicInsert();
|
||||
// dynamicUpdate = hibAnn.dynamicUpdate();
|
||||
|
@ -66,18 +125,64 @@ public class EntityBinder {
|
|||
// }
|
||||
}
|
||||
|
||||
private void bindJpaAnnotation(AnnotationInstance annotation, EntityBinding entityBinding) {
|
||||
if ( annotation == null ) {
|
||||
throw new AssertionFailure( "@Entity cannot be not null when binding an entity" );
|
||||
private Hierarchical getSuperType() {
|
||||
ConfiguredClass parent = entity.getParent();
|
||||
if ( parent == null ) {
|
||||
return null;
|
||||
}
|
||||
String name;
|
||||
if ( annotation.value( "name" ) == null ) {
|
||||
name = StringHelper.unqualify( classToBind.name().toString() );
|
||||
|
||||
EntityBinding parentBinding = meta.getEntityBinding( parent.getName() );
|
||||
if ( parentBinding == null ) {
|
||||
throw new AssertionFailure(
|
||||
"Parent entity " + parent.getName() + " of entity " + entity.getName() + "not yet created!"
|
||||
);
|
||||
}
|
||||
else {
|
||||
name = annotation.value( "name" ).asString();
|
||||
|
||||
return parentBinding.getEntity();
|
||||
}
|
||||
|
||||
private IdType determineIdType() {
|
||||
List<AnnotationInstance> idAnnotations = entity.getClassInfo().annotations().get( JPADotNames.ENTITY );
|
||||
List<AnnotationInstance> embeddedIdAnnotations = entity.getClassInfo()
|
||||
.annotations()
|
||||
.get( JPADotNames.EMBEDDED_ID );
|
||||
|
||||
if ( idAnnotations != null && embeddedIdAnnotations != null ) {
|
||||
throw new MappingException(
|
||||
"@EmbeddedId and @Id cannot be used together. Check the configuration for " + entity.getName() + "."
|
||||
);
|
||||
}
|
||||
entityBinding.setEntity( new Entity( name, null ) );
|
||||
|
||||
if ( embeddedIdAnnotations != null ) {
|
||||
if ( embeddedIdAnnotations.size() == 1 ) {
|
||||
return IdType.EMBEDDED;
|
||||
}
|
||||
else {
|
||||
throw new MappingException( "Multiple @EmbeddedId annotations are not allowed" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( idAnnotations != null ) {
|
||||
if ( idAnnotations.size() == 1 ) {
|
||||
return IdType.SIMPLE;
|
||||
}
|
||||
else {
|
||||
return IdType.COMPOSED;
|
||||
}
|
||||
}
|
||||
|
||||
return IdType.NONE;
|
||||
}
|
||||
|
||||
enum IdType {
|
||||
// single @Id annotation
|
||||
SIMPLE,
|
||||
// multiple @Id annotations
|
||||
COMPOSED,
|
||||
// @EmbeddedId annotation
|
||||
EMBEDDED,
|
||||
// does not contain any identifier mappings
|
||||
NONE
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.metamodel.source.annotations;
|
||||
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
|
@ -43,6 +44,7 @@ public interface JPADotNames {
|
|||
public static final DotName INHERITANCE = DotName.createSimple( Inheritance.class.getName() );
|
||||
|
||||
public static final DotName ID = DotName.createSimple( Id.class.getName() );
|
||||
public static final DotName EMBEDDED_ID = DotName.createSimple( EmbeddedId.class.getName() );
|
||||
public static final DotName ACCESS = DotName.createSimple( Access.class.getName() );
|
||||
public static final DotName TRANSIENT = DotName.createSimple( Transient.class.getName() );
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ import org.hibernate.metamodel.source.internal.MetadataImpl;
|
|||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class FetchProfileBinder {
|
||||
private FetchProfileBinder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds all {@link org.hibernate.annotations.FetchProfiles} and {@link org.hibernate.annotations.FetchProfile} \
|
||||
* annotations to the specified meta data instance.
|
||||
|
|
|
@ -23,15 +23,20 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.source.annotations.util;
|
||||
|
||||
import java.beans.Introspector;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.AnnotationTarget;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.FieldInfo;
|
||||
import org.jboss.jandex.Index;
|
||||
import org.jboss.jandex.Indexer;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -46,6 +51,40 @@ public class JandexHelper {
|
|||
private JandexHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Expects a method or field annotation target and returns the property name for this target
|
||||
*
|
||||
* @param target the annotation target
|
||||
*
|
||||
* @return the property name of the target. For a field it is the field name and for a method name it is
|
||||
* the method name stripped of 'is', 'has' or 'get'
|
||||
*/
|
||||
public static String getPropertyName(AnnotationTarget target) {
|
||||
if ( !( target instanceof MethodInfo || target instanceof FieldInfo ) ) {
|
||||
throw new AssertionFailure( "Unexpected annotation target " + target.toString() );
|
||||
}
|
||||
|
||||
if ( target instanceof FieldInfo ) {
|
||||
return ( (FieldInfo) target ).name();
|
||||
}
|
||||
else {
|
||||
String methodName = ( (MethodInfo) target ).name();
|
||||
if ( methodName.startsWith( "is" ) ) {
|
||||
methodName = Introspector.decapitalize( methodName.substring( 2 ) );
|
||||
}
|
||||
else if ( methodName.startsWith( "has" ) ) {
|
||||
methodName = Introspector.decapitalize( methodName.substring( 3 ) );
|
||||
}
|
||||
else if ( methodName.startsWith( "get" ) ) {
|
||||
methodName = Introspector.decapitalize( methodName.substring( 3 ) );
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure( "Expected a method following the Java Bean notation" );
|
||||
}
|
||||
return methodName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param classInfo the class info from which to retrieve the annotation instance
|
||||
* @param annotationName the annotation to retrieve from the class info
|
||||
|
@ -75,8 +114,9 @@ public class JandexHelper {
|
|||
/**
|
||||
* Creates a jandex index for the specified classes
|
||||
*
|
||||
* @param classLoaderService class loader service
|
||||
* @param classLoaderService class loader service
|
||||
* @param classes the classes to index
|
||||
*
|
||||
* @return an annotation repository w/ all the annotation discovered in the specified classes
|
||||
*/
|
||||
public static Index indexForClass(ClassLoaderService classLoaderService, Class<?>... classes) {
|
||||
|
@ -100,7 +140,7 @@ public class JandexHelper {
|
|||
count++;
|
||||
}
|
||||
builder.append( "]" );
|
||||
throw new HibernateException( "Unable to create annotation index for " + builder.toString());
|
||||
throw new HibernateException( "Unable to create annotation index for " + builder.toString() );
|
||||
}
|
||||
}
|
||||
return indexer.complete();
|
||||
|
|
Loading…
Reference in New Issue