📄 annotationbinder.java
字号:
//$Id: AnnotationBinder.java,v 1.60 2005/02/26 00:57:39 epbernard Exp $package org.hibernate.cfg;import java.lang.reflect.AnnotatedElement;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.Set;import javax.ejb.AccessType;import javax.ejb.AssociationTable;import javax.ejb.Basic;import javax.ejb.CascadeType;import javax.ejb.Column;import javax.ejb.Dependent;import javax.ejb.DependentAttribute;import javax.ejb.DependentObject;import javax.ejb.DiscriminatorType;import javax.ejb.Entity;import javax.ejb.FetchType;import javax.ejb.GeneratorTable;import javax.ejb.GeneratorType;import javax.ejb.Id;import javax.ejb.Inheritance;import javax.ejb.InheritanceJoinColumn;import javax.ejb.InheritanceJoinColumns;import javax.ejb.InheritanceType;import javax.ejb.JoinColumn;import javax.ejb.JoinColumns;import javax.ejb.ManyToMany;import javax.ejb.ManyToOne;import javax.ejb.OneToMany;import javax.ejb.OneToOne;import javax.ejb.SecondaryTable;import javax.ejb.SequenceGenerator;import javax.ejb.TableGenerator;import javax.ejb.Transient;import javax.ejb.UniqueConstraint;import javax.ejb.Version;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.hibernate.AnnotationException;import org.hibernate.AssertionFailure;import org.hibernate.FetchMode;import org.hibernate.MappingException;import org.hibernate.annotations.*;import org.hibernate.cfg.annotations.EntityBinder;import org.hibernate.engine.Versioning;import org.hibernate.id.MultipleHiLoPerTableGenerator;import org.hibernate.id.PersistentIdentifierGenerator;import org.hibernate.id.TableHiLoGenerator;import org.hibernate.mapping.Bag;import org.hibernate.mapping.Collection;import org.hibernate.mapping.Component;import org.hibernate.mapping.DependantValue;import org.hibernate.mapping.IdGenerator;import org.hibernate.mapping.Join;import org.hibernate.mapping.JoinedSubclass;import org.hibernate.mapping.KeyValue;import org.hibernate.mapping.PersistentClass;import org.hibernate.mapping.Property;import org.hibernate.mapping.RootClass;import org.hibernate.mapping.SimpleValue;import org.hibernate.mapping.Subclass;import org.hibernate.mapping.Table;import org.hibernate.mapping.TableOwner;import org.hibernate.mapping.Value;import org.hibernate.persister.entity.JoinedSubclassEntityPersister;import org.hibernate.persister.entity.SingleTableEntityPersister;import org.hibernate.type.ForeignKeyDirection;import org.hibernate.util.ReflectHelper;import org.hibernate.util.StringHelper;/** * JSR 175 annotation binder * Will read the annotation from classes, apply the * principles of the EJB3 spec and produces the Hibernate * configuration-time metamodel (the classes in the <tt>mapping</tt> * package) * * @author Emmanuel Bernard */public final class AnnotationBinder { private static final String GENERATOR_TABLE_NAME_PARAM = "generatorTableName"; public static final String ANNOTATION_STRING_DEFAULT = ""; /* * Some design description * I tried to remove any link to annotation except from the 2 first level of * method call. * It'll enable to: * - facilitate annotation overriding * - mutualize one day xml and annotation binder (probably a dream though) * - split this huge class in smaller mapping oriented classes * * bindSomething usually create the mapping container and is accessed by one of the 2 first level method * makeSomething usually create the mapping container and is accessed by bindSomething[else] * fillSomething take the container into parameter and fill it. * * */ private AnnotationBinder() {} private static final Log log = LogFactory.getLog(AnnotationBinder.class); public static void bindPackage(String packageName, ExtendedMappings mappings) { Package pckg = null; try { pckg = ReflectHelper.classForName(packageName + ".package-info").getPackage(); } catch (ClassNotFoundException cnf) { log.warn("Package not found or wo package-info.java: " + packageName); return; } if ( pckg.isAnnotationPresent(SequenceGenerator.class) ) { SequenceGenerator ann = pckg.getAnnotation(SequenceGenerator.class); IdGenerator idGen = buildIdGenerator(ann); mappings.addGenerator(idGen); log.debug("Add sequence generator with name: " + idGen.getName() ); } if ( pckg.isAnnotationPresent(TableGenerator.class) ) { TableGenerator ann = pckg.getAnnotation(TableGenerator.class); IdGenerator idGen = buildIdGenerator(ann); mappings.addGenerator(idGen); log.debug("Add table generator with name: " + idGen.getName() ); } if ( pckg.isAnnotationPresent(GeneratorTable.class) ) { GeneratorTable ann = pckg.getAnnotation(GeneratorTable.class); Properties params = buildPropertiesFromGeneratorTable(ann); mappings.addGeneratorTable(ann.name(), params); } } private static Properties buildPropertiesFromGeneratorTable(GeneratorTable ann) { Properties params = new Properties(); if ( ! isDefault( ann.pkColumnName() ) ) params.setProperty( MultipleHiLoPerTableGenerator.PK_COLUMN_NAME, ann.pkColumnName() ); if ( ! isDefault( ann.valueColumnName() ) ) params.setProperty( MultipleHiLoPerTableGenerator.VALUE_COLUMN_NAME, ann.valueColumnName() ); if ( ann.table().specified() == true ) { javax.ejb.Table table = ann.table(); if ( ! isDefault( table.name() ) ) params.setProperty( MultipleHiLoPerTableGenerator.ID_TABLE, table.name() ); if ( ! isDefault( table.catalog() ) ) params.setProperty( MultipleHiLoPerTableGenerator.CATALOG, table.catalog() ); if ( ! isDefault( table.schema() ) ) params.setProperty( MultipleHiLoPerTableGenerator.SCHEMA, table.schema() ); //FIXME implements uniqueconstrains } else { params.setProperty( MultipleHiLoPerTableGenerator.ID_TABLE, ann.name() ); } return params; } private static IdGenerator buildIdGenerator(java.lang.annotation.Annotation ann) { IdGenerator idGen = new IdGenerator(); if (ann == null) { idGen = null; } else if (ann instanceof TableGenerator) { TableGenerator tabGen = (TableGenerator) ann; idGen.setName( tabGen.name() ); idGen.setIdentifierGeneratorStrategy( MultipleHiLoPerTableGenerator.class.getName() ); if ( !isDefault( tabGen.tableName() ) ) { idGen.addParam( GENERATOR_TABLE_NAME_PARAM, tabGen.tableName() ); } if ( !isDefault( tabGen.pkColumnValue() ) ) { idGen.addParam( MultipleHiLoPerTableGenerator.PK_VALUE_NAME, tabGen.pkColumnValue() ); } idGen.addParam( TableHiLoGenerator.MAX_LO, String.valueOf( tabGen.allocationSize() ) ); } else if (ann instanceof SequenceGenerator) { SequenceGenerator seqGen = (SequenceGenerator) ann; idGen.setName( seqGen.name() ); idGen.setIdentifierGeneratorStrategy("sequence"); idGen.addParam( org.hibernate.id.SequenceGenerator.SEQUENCE, seqGen.sequenceName() ); //FIXME: work on initialValue() and allocationSize() through SequenceGenerator.PARAMETERS if (seqGen.initialValue() != 0 || seqGen.allocationSize() != 50) { log.warn("Hibernate does not support SequenceGenerator.initialValue() nor SequenceGenerator.allocationSize()"); } } else { throw new AssertionFailure("Unknown Generator annotation: " + ann); } return idGen; } /** * Bind a class having JSR175 annotations * The subclasses <b>have to</b> be binded after its mother class * * @param annotatedClass * @param mappings * @throws MappingException */ public static void bindClass(Class annotatedClass, ExtendedMappings mappings) throws MappingException { //FIXME: enable inheritance to be specified only once per hierarchy //TODO: be more strict with secondarytable allowance (not for ids, not for secondary table join columns etc) //TODO check if its the more convinient default if ( ! mappings.getClassType(annotatedClass).equals(AnnotatedClassType.ENTITY) ) { throw new AnnotationException( "Annotated class should have an @Entity annotation: " + annotatedClass.getName() ); } Class superClass = annotatedClass.getSuperclass(); PersistentClass superEntity = mappings.getClass( superClass.getName() ); if (superEntity == null) { //check if superclass is not a potential persistent class if ( mappings.getClassType(superClass).equals(AnnotatedClassType.ENTITY) ) { throw new AnnotationException( "Subclass has to be binded after it's mother class: " + superClass.getName() ); } } boolean isRootClass = superEntity == null; boolean isSubClass = false; boolean isJoinedSubclass = false; String schema = ""; String table = ""; //might be no @Table annotation on the annotated class String catalog = ""; String discrimValue = null; List uniqueConstraints = new ArrayList(); if (annotatedClass.isAnnotationPresent(javax.ejb.Table.class) ) { javax.ejb.Table tabAnn = (javax.ejb.Table) annotatedClass.getAnnotation(javax.ejb.Table.class); table = tabAnn.name(); schema = tabAnn.schema(); catalog = tabAnn.catalog(); if (tabAnn.uniqueConstraints().length != 0) { for( UniqueConstraint uc : tabAnn.uniqueConstraints() ) { if (! uc.primary() ) { uniqueConstraints.add( uc.columnNames() ); } else { log.warn("@UniqueConstraint(primaryKey=true) not yet supported"); } } } } //discriminator parameters Ejb3DiscriminatorColumn discriminatorColumn = null; boolean singleTableStrategy = true; Ejb3JoinColumn[] joinedColumns = null; if (annotatedClass.isAnnotationPresent(javax.ejb.Inheritance.class) ) { //FIXME: check for homogenous inheritance strategy javax.ejb.Inheritance inhAnn = (javax.ejb.Inheritance) annotatedClass.getAnnotation(javax.ejb.Inheritance.class); if ( inhAnn.strategy().equals(InheritanceType.TABLE_PER_CLASS) ) { singleTableStrategy = false; if (!isRootClass) { throw new AnnotationException("TABLE_PER_CLASS only allows hierarchy leaf mapping"); } } if ( inhAnn.strategy().equals(InheritanceType.JOINED) ) { //mark as joined subclass if needed and prepare thr join column singleTableStrategy = false; isJoinedSubclass = !isRootClass; if (isJoinedSubclass) { InheritanceJoinColumns jcsAnn = (InheritanceJoinColumns) annotatedClass.getAnnotation(InheritanceJoinColumns.class); boolean explicitInheritanceJoinedColumns = jcsAnn != null && jcsAnn.value().length != 0; if (explicitInheritanceJoinedColumns) { int nbrOfInhJoinedColumns = jcsAnn.value().length; InheritanceJoinColumn jcAnn; joinedColumns = new Ejb3JoinColumn[nbrOfInhJoinedColumns]; for (int colIndex = 0 ; colIndex < nbrOfInhJoinedColumns ; colIndex++) { jcAnn = jcsAnn.value()[colIndex]; joinedColumns[colIndex] = Ejb3JoinColumn.buildJoinColumn(jcAnn, superEntity.getIdentifier(), (Map<String, Join>) null, (PropertyHolder) null, mappings); } } else { //FIXME do we support implicit composite PK? HBX-75 InheritanceJoinColumn jcAnn = (InheritanceJoinColumn) annotatedClass.getAnnotation(InheritanceJoinColumn.class); joinedColumns = new Ejb3JoinColumn[1]; joinedColumns[0] = Ejb3JoinColumn.buildJoinColumn(jcAnn, superEntity.getIdentifier(), (Map<String, Join>) null, (PropertyHolder) null, mappings); } log.debug("Joined column(s) created" ); } } if ( inhAnn.strategy().equals(InheritanceType.SINGLE_TABLE) ) { singleTableStrategy = true; if (annotatedClass.isAnnotationPresent(javax.ejb.DiscriminatorColumn.class) ) { javax.ejb.DiscriminatorColumn discAnn = (javax.ejb.DiscriminatorColumn) annotatedClass.getAnnotation(javax.ejb.DiscriminatorColumn.class); if (isRootClass) { discriminatorColumn = Ejb3DiscriminatorColumn.buildDiscriminatorColumn(inhAnn.discriminatorType(), discAnn, mappings); } else { log.warn("Discriminator should not be defined in a subclass, annotation ignored"); } } discrimValue = inhAnn.discriminatorValue(); } } //we now know what kind of persistent entity it is PersistentClass persistentClass; isSubClass = ! isRootClass && singleTableStrategy; //create eprsistent class if (isRootClass) { persistentClass = new RootClass(); } else if (isSubClass) { persistentClass = new Subclass(superEntity); } else { persistentClass = new JoinedSubclass(superEntity); } Proxy proxyAnn = (Proxy) annotatedClass.getAnnotation(Proxy.class); BatchSize sizeAnn = (BatchSize) annotatedClass.getAnnotation(BatchSize.class); Where whereAnn = (Where) annotatedClass.getAnnotation(Where.class); Entity entityAnn = (Entity) annotatedClass.getAnnotation(Entity.class); org.hibernate.annotations.Entity hibEntityAnn = (org.hibernate.annotations.Entity) annotatedClass.getAnnotation( org.hibernate.annotations.Entity.class ); EntityBinder entityBinder = new EntityBinder(entityAnn, hibEntityAnn, annotatedClass, persistentClass, mappings); entityBinder.setDiscriminatorValue(discrimValue); entityBinder.setBatchSize(sizeAnn); entityBinder.setProxy(proxyAnn); entityBinder.setWhere(whereAnn); entityBinder.bindEntity(); //bindEntity(persistentClass, annotatedClass, discrimValue); if (! isSubClass) { Check checkAnn = (Check) annotatedClass.getAnnotation(Check.class); String constraints = checkAnn == null ? null : checkAnn.constraints(); bindTable(persistentClass, schema, catalog, table, uniqueConstraints, constraints, mappings); } PropertyHolder propertyHolder = PropertyHolderBuilder.buildPropertyHolder(persistentClass); Map<String, Join> secondaryTables = new HashMap<String, Join>(); Map<String, Object> secondaryTableJoins = new HashMap<String, Object>(); if (annotatedClass.isAnnotationPresent(javax.ejb.SecondaryTable.class) ) { javax.ejb.SecondaryTable tabAnn = (javax.ejb.SecondaryTable) annotatedClass.getAnnotation(javax.ejb.SecondaryTable.class); prepareForSecondaryTable(tabAnn, persistentClass, secondaryTables, secondaryTableJoins, mappings); } if (annotatedClass.isAnnotationPresent(javax.ejb.SecondaryTables.class) ) { javax.ejb.SecondaryTables tabsAnn = (javax.ejb.SecondaryTables) annotatedClass.getAnnotation(javax.ejb.SecondaryTables.class); for (SecondaryTable tab : tabsAnn.value() ) { prepareForSecondaryTable(tab, persistentClass, secondaryTables, secondaryTableJoins, mappings); } } if (isJoinedSubclass) { JoinedSubclass jsc = (JoinedSubclass) persistentClass; if ( persistentClass.getEntityPersisterClass()==null ) { persistentClass.getRootClass().setEntityPersisterClass(JoinedSubclassEntityPersister.class); } SimpleValue key = new DependantValue( jsc.getTable(), jsc.getIdentifier() ); jsc.setKey(key); key.setCascadeDeleteEnabled(false); bindFk(jsc, joinedColumns, key); jsc.createPrimaryKey(); jsc.createForeignKey(); } else if (isSubClass) { if ( persistentClass.getEntityPersisterClass() == null ) { persistentClass.getRootClass().setEntityPersisterClass(SingleTableEntityPersister.class); } boolean uninilializedDiscrim = persistentClass.getRootClass().getDiscriminator() == null; if (uninilializedDiscrim) { bindDiscriminatorToPersistentClass( persistentClass.getRootClass(), null, secondaryTables, propertyHolder, mappings ); } } else if (singleTableStrategy && isRootClass && discriminatorColumn != null) { bindDiscriminatorToPersistentClass( (RootClass) persistentClass, discriminatorColumn, secondaryTables, propertyHolder, mappings ); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -