[hibernate-commits] Hibernate SVN: r12780 - in trunk/HibernateExt/annotations/src: java/org/hibernate/cfg and 3 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Thu Jul 19 18:12:04 EDT 2007
Author: epbernard
Date: 2007-07-19 18:12:04 -0400 (Thu, 19 Jul 2007)
New Revision: 12780
Added:
trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/Any.java
trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/AnyMetaDef.java
trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/AnyMetaDefs.java
trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/ManyToAny.java
trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/MetaValue.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/AnyTest.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/CharProperty.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/IntegerProperty.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/LongProperty.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/Property.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertyList.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertyMap.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertySet.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/StringProperty.java
trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/package-info.java
Modified:
trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationBinder.java
trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationConfiguration.java
trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/BinderHelper.java
trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/ExtendedMappings.java
trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/annotations/CollectionBinder.java
Log:
ANN-28 support for @Any and @ManyToAny mapping (Alexander Portnov, Alain Mahier)
Added: trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/Any.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/Any.java (rev 0)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/Any.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,45 @@
+//$Id$
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import javax.persistence.Column;
+import javax.persistence.FetchType;
+import static javax.persistence.FetchType.EAGER;
+
+/**
+ * Define a ToOne association pointing to several entity types.
+ * Matching the according entity type is doe through a metadata discriminator column
+ * This kind of mapping should be only marginal.
+ *
+ * @author Emmanuel Bernard
+ */
+ at java.lang.annotation.Target({METHOD, FIELD})
+ at Retention(RUNTIME)
+public @interface Any {
+ /**
+ * Metadata definition used.
+ * If defined, should point to a @AnyMetaDef name
+ * If not defined, the local (ie in the same field or property) @AnyMetaDef is used
+ */
+ String metaDef() default "";
+
+ /**
+ * Metadata discriminator column description, This column will hold the meta value corresponding to the
+ * targeted entity.
+ */
+ Column metaColumn();
+ /**
+ * Defines whether the value of the field or property should be lazily loaded or must be
+ * eagerly fetched. The EAGER strategy is a requirement on the persistence provider runtime
+ * that the value must be eagerly fetched. The LAZY strategy is applied when bytecode
+ * enhancement is used. If not specified, defaults to EAGER.
+ */
+ FetchType fetch() default EAGER;
+ /**
+ * Whether the association is optional. If set to false then a non-null relationship must always exist.
+ */
+ boolean optional() default true;
+}
Added: trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/AnyMetaDef.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/AnyMetaDef.java (rev 0)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/AnyMetaDef.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,40 @@
+//$Id$
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Defines @Any and @manyToAny metadata
+ *
+ * @author Emmanuel Bernard
+ */
+ at java.lang.annotation.Target( { PACKAGE, TYPE, METHOD, FIELD } )
+ at Retention( RUNTIME )
+public @interface AnyMetaDef {
+ /**
+ * If defined, assign a global meta definition name to be used in an @Any or @ManyToAny annotation
+ * If not defined, the metadata applies to the current property or field
+ */
+ String name() default "";
+
+ /**
+ * meta discriminator Hibernate type
+ */
+ String metaType();
+
+ /**
+ * Hibernate type of the id column
+ * @return
+ */
+ String idType();
+
+ /**
+ * Matching discriminator values with their respective entity
+ */
+ MetaValue[] metaValues();
+}
Added: trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/AnyMetaDefs.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/AnyMetaDefs.java (rev 0)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/AnyMetaDefs.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,21 @@
+//$Id$
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.FIELD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Defines @Any and @ManyToAny set of metadata.
+ * Can be defined at the entity level or the package level
+ *
+ * @author Emmanuel Bernard
+ */
+ at java.lang.annotation.Target( { PACKAGE, TYPE } )
+ at Retention( RUNTIME )
+public @interface AnyMetaDefs {
+ AnyMetaDef[] value();
+}
Added: trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/ManyToAny.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/ManyToAny.java (rev 0)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/ManyToAny.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,41 @@
+//$Id$
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.FIELD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import javax.persistence.Column;
+import javax.persistence.FetchType;
+import static javax.persistence.FetchType.EAGER;
+
+/**
+ * Defined a ToMany association pointing to different entity types.
+ * Matching the according entity type is doe through a metadata discriminator column
+ * This kind of mapping should be only marginal.
+ *
+ * @author Emmanuel Bernard
+ */
+ at java.lang.annotation.Target({METHOD, FIELD})
+ at Retention(RUNTIME)
+public @interface ManyToAny {
+ /**
+ * Metadata definition used.
+ * If defined, should point to a @AnyMetaDef name
+ * If not defined, the local (ie in the same field or property) @AnyMetaDef is used
+ */
+ String metaDef() default "";
+
+ /**
+ * Metadata dicriminator column description, This column will hold the meta value corresponding to the
+ * targeted entity.
+ */
+ Column metaColumn();
+ /**
+ * Defines whether the value of the field or property should be lazily loaded or must be
+ * eagerly fetched. The EAGER strategy is a requirement on the persistence provider runtime
+ * that the value must be eagerly fetched. The LAZY strategy is applied when bytecode
+ * enhancement is used. If not specified, defaults to EAGER.
+ */
+ FetchType fetch() default EAGER;
+}
Added: trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/MetaValue.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/MetaValue.java (rev 0)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/annotations/MetaValue.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,18 @@
+//$Id$
+package org.hibernate.annotations;
+
+/**
+ * Represent a discriminator value associated to a given entity type
+ * @author Emmanuel Bernard
+ */
+public @interface MetaValue {
+ /**
+ * entity type
+ */
+ Class targetEntity();
+
+ /**
+ * discriminator value stored in database
+ */
+ String value();
+}
Modified: trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationBinder.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationBinder.java 2007-07-18 21:11:33 UTC (rev 12779)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationBinder.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -95,6 +95,9 @@
import org.hibernate.annotations.Target;
import org.hibernate.annotations.Tuplizers;
import org.hibernate.annotations.Tuplizer;
+import org.hibernate.annotations.AnyMetaDef;
+import org.hibernate.annotations.MetaValue;
+import org.hibernate.annotations.ManyToAny;
import org.hibernate.cfg.annotations.CollectionBinder;
import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.cfg.annotations.Nullability;
@@ -122,6 +125,7 @@
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.UnionSubclass;
import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.Any;
import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
@@ -239,6 +243,7 @@
bindQueries( pckg, mappings );
bindFilterDefs( pckg, mappings );
bindTypeDefs( pckg, mappings );
+ BinderHelper.bindAnyMetaDefs( pckg, mappings );
}
private static void bindQueries(XAnnotatedElement annotatedElement, ExtendedMappings mappings) {
@@ -419,6 +424,7 @@
bindQueries( annotatedClass, mappings );
bindFilterDefs( annotatedClass, mappings );
bindTypeDefs( annotatedClass, mappings );
+ BinderHelper.bindAnyMetaDefs( annotatedClass, mappings );
String schema = "";
String table = ""; //might be no @Table annotation on the annotated class
@@ -1027,6 +1033,15 @@
.equals( void.class ) ) {
return true;
}
+ else if ( p.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
+ return true;
+ }
+ else if ( p.isAnnotationPresent( ManyToAny.class ) ) {
+ if ( ! p.isCollection() && ! p.isArray() ) {
+ throw new AnnotationException( "@ManyToAny used on a non collection non array property: " + p.getName() );
+ }
+ return true;
+ }
else if ( p.isAnnotationPresent( Type.class ) ) {
return true;
}
@@ -1185,6 +1200,10 @@
propertyHolder, inferredData.getPropertyName(), mappings
);
}
+ else if ( joinColumns == null && property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
+ throw new AnnotationException("@Any requires an explicit @JoinColumn(s): "
+ + StringHelper.qualify( propertyHolder.getPath(), property.getName() ) );
+ }
if ( columns == null && !property.isAnnotationPresent( ManyToMany.class ) ) {
//useful for collection of embedded elements
columns = Ejb3Column.buildColumnFromAnnotation(
@@ -1266,11 +1285,10 @@
}
log.debug( inferredData.getPropertyName() + " is a version property" );
RootClass rootClass = (RootClass) propertyHolder.getPersistentClass();
- boolean lazy = false;
PropertyBinder propBinder = new PropertyBinder();
propBinder.setName( inferredData.getPropertyName() );
propBinder.setReturnedClassName( inferredData.getTypeName() );
- propBinder.setLazy( lazy );
+ propBinder.setLazy( false );
propBinder.setPropertyAccessorName( inferredData.getDefaultAccess() );
propBinder.setColumns( columns );
propBinder.setHolder( propertyHolder ); //PropertyHolderBuilder.buildPropertyHolder(rootClass)
@@ -1358,9 +1376,36 @@
inferredData, ann.mappedBy(), trueOneToOne, isIdentifierMapper, inSecondPass, mappings
);
}
+ else if ( property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
+
+ //check validity
+ if ( property.isAnnotationPresent( Column.class )
+ || property.isAnnotationPresent( Columns.class ) ) {
+ throw new AnnotationException( "@Column(s) not allowed on a @Any property: "
+ + StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() ) );
+ }
+
+ Cascade hibernateCascade = property.getAnnotation( Cascade.class );
+ NotFound notFound = property.getAnnotation( NotFound.class );
+ boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
+ OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
+ boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
+ JoinTable assocTable = property.getAnnotation( JoinTable.class );
+ if ( assocTable != null ) {
+ Join join = propertyHolder.addJoin( assocTable, false );
+ for ( Ejb3JoinColumn joinColumn : joinColumns ) {
+ joinColumn.setSecondaryTableName( join.getTable().getName() );
+ }
+ }
+ bindAny( getCascadeStrategy( null, hibernateCascade ), //@Any has not cascade attribute
+ joinColumns, onDeleteCascade, nullability,
+ propertyHolder, inferredData, entityBinder,
+ isIdentifierMapper, mappings );
+ }
else if ( property.isAnnotationPresent( OneToMany.class )
|| property.isAnnotationPresent( ManyToMany.class )
- || property.isAnnotationPresent( CollectionOfElements.class ) ) {
+ || property.isAnnotationPresent( CollectionOfElements.class )
+ || property.isAnnotationPresent( ManyToAny.class ) ) {
OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class );
ManyToMany manyToManyAnn = property.getAnnotation( ManyToMany.class );
CollectionOfElements collectionOfElementsAnn = property.getAnnotation( CollectionOfElements.class );
@@ -1468,6 +1513,7 @@
collectionBinder.setElementColumns( elementColumns );
collectionBinder.setProperty( property );
+ //TODO enhance exception with @ManyToAny and @CollectionOfElements
if ( oneToManyAnn != null && manyToManyAnn != null ) {
throw new AnnotationException(
"@OneToMany and @ManyToMany on the same property is not allowed: "
@@ -1511,6 +1557,14 @@
collectionBinder.setCascadeStrategy( getCascadeStrategy( manyToManyAnn.cascade(), hibernateCascade ) );
collectionBinder.setOneToMany( false );
}
+ else if ( property.isAnnotationPresent( ManyToAny.class) ) {
+ mappedBy = "";
+ collectionBinder.setTargetEntity(
+ mappings.getReflectionManager().toXClass( void.class )
+ );
+ collectionBinder.setCascadeStrategy( getCascadeStrategy( null, hibernateCascade ) );
+ collectionBinder.setOneToMany( false );
+ }
collectionBinder.setMappedBy( mappedBy );
bindJoinedTableAssociation(
assocTable, mappings, entityBinder, collectionBinder, propertyHolder, inferredData, mappedBy
@@ -2029,6 +2083,40 @@
}
}
+ private static void bindAny(
+ String cascadeStrategy, Ejb3JoinColumn[] columns, boolean cascadeOnDelete, Nullability nullability,
+ PropertyHolder propertyHolder, PropertyData inferredData, EntityBinder entityBinder,
+ boolean isIdentifierMapper, ExtendedMappings mappings
+ ) {
+ org.hibernate.annotations.Any anyAnn = inferredData.getProperty().getAnnotation( org.hibernate.annotations.Any.class );
+ if (anyAnn == null) {
+ throw new AssertionFailure( "Missing @Any annotation: "
+ + StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() ) );
+ }
+ Any value = BinderHelper.buildAnyValue( anyAnn.metaDef(), columns, anyAnn.metaColumn(), inferredData,
+ cascadeOnDelete, nullability, propertyHolder, entityBinder, anyAnn.optional(), mappings );
+
+ PropertyBinder binder = new PropertyBinder();
+ binder.setName( inferredData.getPropertyName() );
+ binder.setValue( value );
+
+ binder.setLazy( anyAnn.fetch() == FetchType.LAZY );
+ //binder.setCascade(cascadeStrategy);
+ if ( isIdentifierMapper ) {
+ binder.setInsertable( false );
+ binder.setUpdatable( false );
+ }
+ else {
+ binder.setInsertable( columns[0].isInsertable() );
+ binder.setUpdatable( columns[0].isUpdatable() );
+ }
+ binder.setPropertyAccessorName( inferredData.getDefaultAccess() );
+ binder.setCascade( cascadeStrategy );
+ Property prop = binder.make();
+ //composite FK columns are in the same table so its OK
+ propertyHolder.addProperty( prop, columns );
+ }
+
private static String generatorType(GenerationType generatorEnum) {
switch (generatorEnum) {
case IDENTITY:
Modified: trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationConfiguration.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationConfiguration.java 2007-07-18 21:11:33 UTC (rev 12779)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationConfiguration.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -37,6 +37,7 @@
import org.hibernate.SessionFactory;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.cfg.annotations.Version;
import org.hibernate.cfg.annotations.reflection.EJB3ReflectionManager;
import org.hibernate.event.PreInsertEventListener;
@@ -82,6 +83,7 @@
private Map<Table, List<String[]>> tableUniqueConstraints;
private Map<String, String> mappedByResolver;
private Map<String, String> propertyRefResolver;
+ private Map<String, AnyMetaDef> anyMetaDefs;
private List<XClass> annotatedClasses;
private Map<String, XClass> annotatedClassEntities;
private Map<String, Document> hbmEntities;
@@ -198,6 +200,7 @@
tableUniqueConstraints,
mappedByResolver,
propertyRefResolver,
+ anyMetaDefs,
reflectionManager
);
}
@@ -236,6 +239,7 @@
hbmDocuments = new ArrayList<Document>();
namingStrategy = EJB3NamingStrategy.INSTANCE;
setEntityResolver( new EJB3DTDEntityResolver() );
+ anyMetaDefs = new HashMap<String, AnyMetaDef>();
reflectionManager = new EJB3ReflectionManager();
}
Modified: trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/BinderHelper.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/BinderHelper.java 2007-07-18 21:11:33 UTC (rev 12779)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/BinderHelper.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -15,9 +15,21 @@
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.annotations.AnyMetaDef;
+import org.hibernate.annotations.MetaValue;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+import org.hibernate.annotations.Parameter;
+import org.hibernate.annotations.AnyMetaDefs;
+import org.hibernate.annotations.common.reflection.XAnnotatedElement;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XPackage;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.MultipleHiLoPerTableGenerator;
import org.hibernate.cfg.annotations.TableBinder;
+import org.hibernate.cfg.annotations.Nullability;
+import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
@@ -29,7 +41,10 @@
import org.hibernate.mapping.Value;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.IdGenerator;
+import org.hibernate.mapping.Any;
import org.hibernate.util.StringHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* @author Emmanuel Bernard
@@ -37,6 +52,7 @@
public class BinderHelper {
public static final String ANNOTATION_STRING_DEFAULT = "";
+ private static Log log = LogFactory.getLog( BinderHelper.class );
private BinderHelper() {
}
@@ -437,4 +453,105 @@
return annotationString != null && annotationString.length() == 0;
//equivalent to (but faster) ANNOTATION_STRING_DEFAULT.equals( annotationString );
}
+
+ public static Any buildAnyValue(String anyMetaDefName, Ejb3JoinColumn[] columns, javax.persistence.Column metaColumn, PropertyData inferredData,
+ boolean cascadeOnDelete, Nullability nullability, PropertyHolder propertyHolder,
+ EntityBinder entityBinder, boolean optional, ExtendedMappings mappings) {
+ //All FK columns should be in the same table
+ Any value = new Any( columns[0].getTable() );
+ AnyMetaDef metaAnnDef = inferredData.getProperty().getAnnotation( AnyMetaDef.class );
+
+ if ( metaAnnDef != null ) {
+ //local has precedence over general and can be mapped for future reference if named
+ bindAnyMetaDefs( inferredData.getProperty(), mappings );
+ }
+ else {
+ metaAnnDef = mappings.getAnyMetaDef( anyMetaDefName );
+ }
+ if (metaAnnDef != null) {
+ value.setIdentifierType( metaAnnDef.idType() );
+ value.setMetaType( metaAnnDef.metaType() );
+
+ HashMap values = new HashMap();
+ org.hibernate.type.Type metaType = TypeFactory.heuristicType( value.getMetaType() );
+ for (MetaValue metaValue : metaAnnDef.metaValues() ) {
+ try {
+ Object discrim = ( (org.hibernate.type.DiscriminatorType) metaType ).stringToObject( metaValue
+ .value() );
+ String entityName = metaValue.targetEntity().getName();
+ values.put( discrim, entityName );
+ }
+ catch (ClassCastException cce) {
+ throw new MappingException( "metaType was not a DiscriminatorType: "
+ + metaType.getName() );
+ }
+ catch (Exception e) {
+ throw new MappingException( "could not interpret metaValue", e );
+ }
+ }
+ if ( !values.isEmpty() ) value.setMetaValues( values );
+ }
+ else {
+ throw new AnnotationException( "Unable to find @AnyMetaDef for an @(ManyTo)Any mapping: "
+ + StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() ) );
+ }
+
+ value.setCascadeDeleteEnabled( cascadeOnDelete );
+ if ( !optional ) {
+ for ( Ejb3JoinColumn column : columns ) {
+ column.setNullable( false );
+ }
+ }
+
+ Ejb3Column[] metaColumns = Ejb3Column.buildColumnFromAnnotation( new javax.persistence.Column[] { metaColumn }, null,
+ nullability, propertyHolder, inferredData, entityBinder.getSecondaryTables(), mappings );
+ //set metaColumn to the right table
+ for (Ejb3Column column : metaColumns) {
+ column.setTable( value.getTable() );
+ }
+ //meta column
+ for ( Ejb3Column column : metaColumns ) {
+ column.linkWithValue( value );
+ }
+
+ //id columns
+ final String propertyName = inferredData.getPropertyName();
+ Ejb3Column.checkPropertyConsistency( columns, propertyHolder.getEntityName() + propertyName );
+ for ( Ejb3JoinColumn column : columns ) {
+ column.linkWithValue( value );
+ }
+ return value;
+ }
+
+ public static void bindAnyMetaDefs(XAnnotatedElement annotatedElement, ExtendedMappings mappings) {
+ AnyMetaDef defAnn = annotatedElement.getAnnotation( AnyMetaDef.class );
+ AnyMetaDefs defsAnn = annotatedElement.getAnnotation( AnyMetaDefs.class );
+ boolean mustHaveName = XClass.class.isAssignableFrom( annotatedElement.getClass() )
+ || XPackage.class.isAssignableFrom( annotatedElement.getClass() );
+ if ( defAnn != null ) {
+ checkAnyMetaDefValidity( mustHaveName, defAnn, annotatedElement );
+ bindAnyMetaDef( defAnn, mappings );
+ }
+ if ( defsAnn != null ) {
+ for ( AnyMetaDef def : defsAnn.value() ) {
+ checkAnyMetaDefValidity( mustHaveName, def, annotatedElement );
+ bindAnyMetaDef( def, mappings );
+ }
+ }
+ }
+
+ private static void checkAnyMetaDefValidity(boolean mustHaveName, AnyMetaDef defAnn, XAnnotatedElement annotatedElement) {
+ if ( mustHaveName && isDefault( defAnn.name() ) ) {
+ String name = XClass.class.isAssignableFrom( annotatedElement.getClass() ) ?
+ ( (XClass) annotatedElement ).getName() :
+ ( (XPackage) annotatedElement ).getName();
+ throw new AnnotationException( "@AnyMetaDef.name cannot be null on an entity or a package: " + name);
+ }
+ }
+
+ private static void bindAnyMetaDef(AnyMetaDef defAnn, ExtendedMappings mappings) {
+ if ( isDefault( defAnn.name() ) ) return; //don't map not named definitions
+ if ( log.isInfoEnabled() ) log.info( "Binding Any Meta definition: " + defAnn.name() );
+ mappings.addAnyMetaDef( defAnn );
+ }
}
Modified: trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/ExtendedMappings.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/ExtendedMappings.java 2007-07-18 21:11:33 UTC (rev 12779)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/ExtendedMappings.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -13,6 +13,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.MappingException;
+import org.hibernate.AnnotationException;
import org.hibernate.engine.NamedQueryDefinition;
import org.hibernate.engine.NamedSQLQueryDefinition;
import org.hibernate.engine.ResultSetMappingDefinition;
@@ -22,6 +23,7 @@
import org.hibernate.mapping.Table;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.AnyMetaDef;
/**
* Allow annotation related mappings
@@ -46,6 +48,7 @@
private final Set<String> defaultNamedNativeQueryNames;
private final Set<String> defaultSqlResulSetMappingNames;
private final Set<String> defaultNamedGenerators;
+ private final Map<String, AnyMetaDef> anyMetaDefs;
ExtendedMappings(
Map classes, Map collections, Map tables, Map queries, Map sqlqueries, Map sqlResultSetMappings,
@@ -60,6 +63,7 @@
Map<Table, List<String[]>> tableUniqueConstraints,
Map<String, String> mappedByResolver,
Map<String, String> propertyRefResolver,
+ Map<String, AnyMetaDef> anyMetaDefs,
ReflectionManager reflectionManager
) {
super(
@@ -92,6 +96,7 @@
this.defaultNamedNativeQueryNames = defaultNamedNativeQueryNames;
this.defaultSqlResulSetMappingNames = defaultSqlResulSetMappingNames;
this.defaultNamedGenerators = defaultNamedGenerators;
+ this.anyMetaDefs = anyMetaDefs;
}
public void addGenerator(IdGenerator generator) throws MappingException {
@@ -263,4 +268,15 @@
public Map getClasses() {
return classes;
}
+
+ public void addAnyMetaDef(AnyMetaDef defAnn) {
+ if ( anyMetaDefs.containsKey( defAnn.name() ) ) {
+ throw new AnnotationException("Two @AnyMetaDef with the same name defined: " + defAnn.name() );
+ }
+ anyMetaDefs.put( defAnn.name(), defAnn );
+ }
+
+ public AnyMetaDef getAnyMetaDef(String name) {
+ return anyMetaDefs.get( name );
+ }
}
\ No newline at end of file
Modified: trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/annotations/CollectionBinder.java
===================================================================
--- trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/annotations/CollectionBinder.java 2007-07-18 21:11:33 UTC (rev 12779)
+++ trunk/HibernateExt/annotations/src/java/org/hibernate/cfg/annotations/CollectionBinder.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -48,6 +48,7 @@
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.OptimisticLock;
import org.hibernate.annotations.Persister;
+import org.hibernate.annotations.ManyToAny;
import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.BinderHelper;
@@ -61,6 +62,7 @@
import org.hibernate.cfg.PropertyHolderBuilder;
import org.hibernate.cfg.PropertyPreloadedData;
import org.hibernate.cfg.SecondPass;
+import org.hibernate.cfg.PropertyInferredData;
import org.hibernate.mapping.Backref;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
@@ -75,6 +77,7 @@
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table;
+import org.hibernate.mapping.Any;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.util.StringHelper;
@@ -299,8 +302,6 @@
//set laziness
defineFetchingStrategy();
- //collection.setFetchMode( fetchMode );
- //collection.setLazy( fetchMode == FetchMode.SELECT );
collection.setBatchSize( batchSize );
if ( orderBy != null && hqlOrderBy != null ) {
throw new AnnotationException(
@@ -391,18 +392,17 @@
mappings.addMappedBy( getCollectionType().getName(), mappedBy, propertyName );
}
//TODO reducce tableBinder != null and oneToMany
- //FIXME collection of elements shouldn't be executed as a secondpass
+ XClass collectionType = getCollectionType();
SecondPass sp = getSecondPass(
fkJoinColumns,
joinColumns,
inverseJoinColumns,
elementColumns,
mapKeyColumns, mapKeyManyToManyColumns, isEmbedded,
- property, getCollectionType(),
+ property, collectionType,
ignoreNotFound, oneToMany,
tableBinder, mappings
);
- XClass collectionType = getCollectionType();
if ( collectionType.isAnnotationPresent( Embeddable.class )
|| property.isAnnotationPresent( CollectionOfElements.class ) ) {
// do it right away, otherwise @ManyToon on composite element call addSecondPass
@@ -439,6 +439,7 @@
OneToMany oneToMany = property.getAnnotation( OneToMany.class );
ManyToMany manyToMany = property.getAnnotation( ManyToMany.class );
CollectionOfElements elements = property.getAnnotation( CollectionOfElements.class );
+ ManyToAny manyToAny = property.getAnnotation( ManyToAny.class );
FetchType fetchType;
if ( oneToMany != null ) {
fetchType = oneToMany.fetch();
@@ -449,6 +450,9 @@
else if ( elements != null ) {
fetchType = elements.fetch();
}
+ else if ( manyToAny != null ) {
+ fetchType = FetchType.LAZY;
+ }
else {
throw new AssertionFailure(
"Define fetch strategy on a property not annotated with @ManyToOne nor @OneToMany nor @CollectionOfElements"
@@ -645,6 +649,8 @@
}
}
+
+
private void bindFilters(boolean hasAssociationTable) {
Filter simpleFilter = property.getAnnotation( Filter.class );
//set filtering
@@ -1020,6 +1026,7 @@
PersistentClass collectionEntity = (PersistentClass) persistentClasses.get( collType.getName() );
boolean isCollectionOfEntities = collectionEntity != null;
+ ManyToAny anyAnn = property.getAnnotation( ManyToAny.class );
if ( log.isDebugEnabled() ) {
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
if ( isCollectionOfEntities && unique ) {
@@ -1028,6 +1035,9 @@
else if ( isCollectionOfEntities ) {
log.debug( "Binding as ManyToMany: " + path );
}
+ else if ( anyAnn != null ) {
+ log.debug( "Binding a ManyToAny: " + path );
+ }
else {
log.debug( "Binding a collection of element: " + path );
}
@@ -1040,6 +1050,14 @@
"Use of @OneToMany or @ManyToMany targeting an unmapped class: " + path + "[" + collType + "]"
);
}
+ else if ( anyAnn != null ) {
+ if (! property.isAnnotationPresent( JoinTable.class ) ) {
+ String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
+ throw new AnnotationException(
+ "@JoinTable is mandatory when @ManyToAny is used: " + path
+ );
+ }
+ }
else {
JoinTable joinTableAnn = property.getAnnotation( JoinTable.class );
if ( joinTableAnn != null && joinTableAnn.inverseJoinColumns().length > 0 ) {
@@ -1144,6 +1162,19 @@
String fkName = fk != null ? fk.inverseName() : "";
if ( ! BinderHelper.isDefault( fkName ) ) element.setForeignKeyName( fkName );
}
+ else if ( anyAnn != null ) {
+ //@ManyToAny
+ //Make sure that collTyp is never used during the @ManyToAny branch: it will be set to void.class
+ PropertyData inferredData = new PropertyInferredData(property, "unsupported", mappings.getReflectionManager() );
+ //override the table
+ for ( Ejb3Column column : inverseJoinColumns ) {
+ column.setTable( collValue.getCollectionTable() );
+ }
+ Any any = BinderHelper.buildAnyValue( anyAnn.metaDef(), inverseJoinColumns, anyAnn.metaColumn(),
+ inferredData, cascadeDeleteEnabled, Nullability.NO_CONSTRAINT,
+ propertyHolder, new EntityBinder(), true, mappings );
+ collValue.setElement( any );
+ }
else {
XClass elementClass;
AnnotatedClassType classType;
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/AnyTest.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/AnyTest.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/AnyTest.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,158 @@
+package org.hibernate.test.annotations.any;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.test.annotations.TestCase;
+
+public class AnyTest extends TestCase {
+
+ public void testDefaultAnyAssociation() {
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+
+ PropertySet set1 = new PropertySet( "string" );
+ Property property = new StringProperty( "name", "Alex" );
+ set1.setSomeProperty( property );
+ set1.addGeneratedProperty( property );
+ s.save( set1 );
+
+ PropertySet set2 = new PropertySet( "integer" );
+ property = new IntegerProperty( "age", 33 );
+ set2.setSomeProperty( property );
+ set2.addGeneratedProperty( property );
+ s.save( set2 );
+
+ s.flush();
+ s.clear();
+
+ Query q = s
+ .createQuery( "select s from PropertySet s where name = :name" );
+ q.setString( "name", "string" );
+ PropertySet result = (PropertySet) q.uniqueResult();
+
+ assertNotNull( result );
+ assertNotNull( result.getSomeProperty() );
+ assertTrue( result.getSomeProperty() instanceof StringProperty );
+ assertEquals( "Alex", result.getSomeProperty().asString() );
+ assertNotNull( result.getGeneralProperties() );
+ assertEquals( 1, result.getGeneralProperties().size() );
+ assertEquals( "Alex", result.getGeneralProperties().get( 0 ).asString() );
+
+ q.setString( "name", "integer" );
+ result = (PropertySet) q.uniqueResult();
+ assertNotNull( result );
+ assertNotNull( result.getSomeProperty() );
+ assertTrue( result.getSomeProperty() instanceof IntegerProperty );
+ assertEquals( "33", result.getSomeProperty().asString() );
+ assertNotNull( result.getGeneralProperties() );
+ assertEquals( 1, result.getGeneralProperties().size() );
+ assertEquals( "33", result.getGeneralProperties().get( 0 ).asString() );
+
+ t.rollback();
+ s.close();
+ }
+
+ public void testManyToAnyWithMap() throws Exception {
+
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+
+ PropertyMap map = new PropertyMap( "sample" );
+ map.getProperties().put( "name", new StringProperty( "name", "Alex" ) );
+ map.getProperties().put( "age", new IntegerProperty( "age", 33 ) );
+
+ s.save( map );
+
+ s.flush();
+ s.clear();
+
+ Query q = s
+ .createQuery( "SELECT map FROM PropertyMap map WHERE map.name = :name" );
+ q.setString( "name", "sample" );
+ PropertyMap actualMap = (PropertyMap) q.uniqueResult();
+
+ assertNotNull( actualMap );
+ assertNotNull( actualMap.getProperties() );
+
+ Property property = actualMap.getProperties().get( "name" );
+ assertNotNull( property );
+ assertTrue( property instanceof StringProperty );
+ assertEquals( "Alex", property.asString() );
+
+ property = actualMap.getProperties().get( "age" );
+ assertNotNull( property );
+ assertTrue( property instanceof IntegerProperty );
+ assertEquals( "33", property.asString() );
+
+ t.rollback();
+ s.close();
+
+ }
+
+ public void testMetaDataUseWithManyToAny() throws Exception {
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+
+ PropertyList list = new PropertyList( "sample" );
+ StringProperty stringProperty = new StringProperty( "name", "Alex" );
+ IntegerProperty integerProperty = new IntegerProperty( "age", 33 );
+ LongProperty longProperty = new LongProperty( "distance", 121L );
+ CharProperty charProp = new CharProperty( "Est", 'E' );
+
+ list.setSomeProperty( longProperty );
+
+ list.addGeneratedProperty( stringProperty );
+ list.addGeneratedProperty( integerProperty );
+ list.addGeneratedProperty( longProperty );
+ list.addGeneratedProperty( charProp );
+
+ s.save( list );
+
+ s.flush();
+ s.clear();
+
+ Query q = s
+ .createQuery( "SELECT list FROM PropertyList list WHERE list.name = :name" );
+ q.setString( "name", "sample" );
+ PropertyList<Property> actualList = (PropertyList<Property>) q
+ .uniqueResult();
+
+ assertNotNull( actualList );
+ assertNotNull( actualList.getGeneralProperties() );
+ assertEquals( 4, actualList.getGeneralProperties().size() );
+
+ Property property = actualList.getSomeProperty();
+ assertNotNull( property );
+ assertTrue( property instanceof LongProperty );
+ assertEquals( "121", property.asString() );
+
+ assertEquals( "Alex", actualList.getGeneralProperties().get( 0 )
+ .asString() );
+ assertEquals( "33", actualList.getGeneralProperties().get( 1 ).asString() );
+ assertEquals( "121", actualList.getGeneralProperties().get( 2 ).asString() );
+ assertEquals( "E", actualList.getGeneralProperties().get( 3 ).asString() );
+
+ t.rollback();
+ s.close();
+ }
+
+ @Override
+ protected Class[] getMappings() {
+ return new Class[] {
+ StringProperty.class,
+ IntegerProperty.class,
+ LongProperty.class,
+ PropertySet.class,
+ PropertyMap.class,
+ PropertyList.class,
+ CharProperty.class
+ };
+ }
+
+ protected String[] getAnnotatedPackages() {
+ return new String[] {
+ "org.hibernate.test.annotations.any"
+ };
+ }
+}
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/CharProperty.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/CharProperty.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/CharProperty.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,57 @@
+package org.hibernate.test.annotations.any;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+ at Entity
+ at Table( name = "char_property" )
+public class CharProperty implements Property {
+ private Integer id;
+
+ private String name;
+
+ private Character value;
+
+ public CharProperty() {
+ super();
+ }
+
+ public CharProperty(String name, Character value) {
+ super();
+ this.name = name;
+ this.value = value;
+ }
+
+ public String asString() {
+ return Character.toString( value );
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Id
+ @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Character getValue() {
+ return value;
+ }
+
+ public void setValue(Character value) {
+ this.value = value;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/IntegerProperty.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/IntegerProperty.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/IntegerProperty.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,56 @@
+package org.hibernate.test.annotations.any;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+ at Entity
+ at Table(name="int_property")
+public class IntegerProperty implements Property {
+ private Integer id;
+ private String name;
+ private Integer value;
+
+ public IntegerProperty() {
+ super();
+ }
+
+ public IntegerProperty(String name, Integer value) {
+ super();
+ this.name = name;
+ this.value = value;
+ }
+
+ public String asString() {
+ return Integer.toString(value);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Id
+ @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getValue() {
+ return value;
+ }
+
+ public void setValue(Integer value) {
+ this.value = value;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+
+}
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/LongProperty.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/LongProperty.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/LongProperty.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,57 @@
+package org.hibernate.test.annotations.any;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+ at Entity
+ at Table(name = "long_property")
+public class LongProperty implements Property {
+ private Integer id;
+
+ private String name;
+
+ private Long value;
+
+ public LongProperty() {
+ super();
+ }
+
+ public LongProperty(String name, Long value) {
+ super();
+ this.name = name;
+ this.value = value;
+ }
+
+ public String asString() {
+ return Long.toString(value);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Id
+ @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Long getValue() {
+ return value;
+ }
+
+ public void setValue(Long value) {
+ this.value = value;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/Property.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/Property.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/Property.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,7 @@
+package org.hibernate.test.annotations.any;
+
+public interface Property {
+
+ public String getName();
+ public String asString();
+}
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertyList.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertyList.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertyList.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,85 @@
+package org.hibernate.test.annotations.any;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.JoinTable;
+import javax.persistence.Column;
+import javax.persistence.JoinColumn;
+
+import org.hibernate.annotations.ManyToAny;
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.IndexColumn;
+import org.hibernate.annotations.Any;
+import org.hibernate.annotations.CascadeType;
+
+ at Entity
+ at Table( name = "property_list" )
+public class PropertyList<T extends Property> {
+ private Integer id;
+
+ private String name;
+
+ private T someProperty;
+
+ private List<T> generalProperties = new ArrayList<T>();
+
+ public PropertyList() {
+ super();
+ }
+
+ public PropertyList(String name) {
+ this.name = name;
+ }
+
+ @ManyToAny( metaDef = "Property", metaColumn = @Column(name = "property_type") )
+ @Cascade( { org.hibernate.annotations.CascadeType.ALL })
+ @JoinTable(name = "list_properties",
+ joinColumns = @JoinColumn(name = "obj_id"),
+ inverseJoinColumns = @JoinColumn(name = "property_id")
+ )
+ @IndexColumn(name = "prop_index")
+ public List<T> getGeneralProperties() {
+ return generalProperties;
+ }
+
+ public void setGeneralProperties(List<T> generalProperties) {
+ this.generalProperties = generalProperties;
+ }
+
+ @Id
+ @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Any( metaDef = "Property", metaColumn = @Column(name = "property_type") )
+ @Cascade( CascadeType.ALL )
+ @JoinColumn(name = "property_id")
+ public T getSomeProperty() {
+ return someProperty;
+ }
+
+ public void setSomeProperty(T someProperty) {
+ this.someProperty = someProperty;
+ }
+
+ public void addGeneratedProperty(T property) {
+ this.generalProperties.add( property );
+ }
+}
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertyMap.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertyMap.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertyMap.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,74 @@
+package org.hibernate.test.annotations.any;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.Table;
+
+import org.hibernate.annotations.AnyMetaDef;
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.ManyToAny;
+import org.hibernate.annotations.MapKey;
+import org.hibernate.annotations.MetaValue;
+
+ at Entity
+ at Table( name = "property_map" )
+public class PropertyMap {
+ private Integer id;
+ private String name;
+
+ private Map<String, Property> properties = new HashMap<String, Property>();
+
+ public PropertyMap(String name) {
+ this.name = name;
+ }
+
+ public PropertyMap() {
+ super();
+ }
+
+ @Id
+ @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @ManyToAny( metaColumn = @Column( name = "property_type" ) )
+ @AnyMetaDef(
+ idType = "integer", metaType = "string",
+ metaValues = {
+ @MetaValue( value = "S", targetEntity = StringProperty.class ),
+ @MetaValue( value = "I", targetEntity = IntegerProperty.class ) } )
+ @Cascade( org.hibernate.annotations.CascadeType.ALL )
+ @JoinTable(
+ name = "map_properties",
+ joinColumns = @JoinColumn( name = "map_id" ),
+ inverseJoinColumns = @JoinColumn( name = "property_id" ) )
+ @MapKey( columns = { @Column( name = "map_key" ) } )
+ public Map<String, Property> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map<String, Property> properties) {
+ this.properties = properties;
+ }
+
+
+}
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertySet.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertySet.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/PropertySet.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,90 @@
+package org.hibernate.test.annotations.any;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.Table;
+
+import org.hibernate.annotations.Any;
+import org.hibernate.annotations.AnyMetaDef;
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
+import org.hibernate.annotations.ManyToAny;
+import org.hibernate.annotations.MetaValue;
+
+ at Entity
+ at Table( name = "property_set" )
+public class PropertySet {
+ private Integer id;
+ private String name;
+ private Property someProperty;
+
+ private List<Property> generalProperties = new ArrayList<Property>();
+
+ public PropertySet() {
+ super();
+ }
+
+ public PropertySet(String name) {
+ this.name = name;
+ }
+
+ @ManyToAny(
+ metaColumn = @Column( name = "property_type" ) )
+ @AnyMetaDef( idType = "integer", metaType = "string",
+ metaValues = {
+ @MetaValue( value = "S", targetEntity = StringProperty.class ),
+ @MetaValue( value = "I", targetEntity = IntegerProperty.class ) } )
+ @Cascade( { org.hibernate.annotations.CascadeType.ALL } )
+ @JoinTable( name = "obj_properties", joinColumns = @JoinColumn( name = "obj_id" ),
+ inverseJoinColumns = @JoinColumn( name = "property_id" ) )
+ public List<Property> getGeneralProperties() {
+ return generalProperties;
+ }
+
+ public void setGeneralProperties(List<Property> generalProperties) {
+ this.generalProperties = generalProperties;
+ }
+
+ @Id
+ @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Any( metaColumn = @Column( name = "property_type" ) )
+ @Cascade( value = { CascadeType.ALL } )
+ @AnyMetaDef( idType = "integer", metaType = "string", metaValues = {
+ @MetaValue( value = "S", targetEntity = StringProperty.class ),
+ @MetaValue( value = "I", targetEntity = IntegerProperty.class )
+ } )
+ @JoinColumn( name = "property_id" )
+ public Property getSomeProperty() {
+ return someProperty;
+ }
+
+ public void setSomeProperty(Property someProperty) {
+ this.someProperty = someProperty;
+ }
+
+ public void addGeneratedProperty(Property property) {
+ this.generalProperties.add( property );
+ }
+}
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/StringProperty.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/StringProperty.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/StringProperty.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,54 @@
+package org.hibernate.test.annotations.any;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+ at Entity
+ at Table(name="string_property")
+public class StringProperty implements Property {
+ private Integer id;
+ private String name;
+ private String value;
+
+ public StringProperty() {
+ super();
+ }
+
+ public StringProperty(String name, String value) {
+ super();
+ this.name = name;
+ this.value = value;
+ }
+
+ @Id
+ @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String asString() {
+ return value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
Added: trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/package-info.java
===================================================================
--- trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/package-info.java (rev 0)
+++ trunk/HibernateExt/annotations/src/test/org/hibernate/test/annotations/any/package-info.java 2007-07-19 22:12:04 UTC (rev 12780)
@@ -0,0 +1,16 @@
+//$Id:
+ at AnyMetaDefs(
+ @AnyMetaDef( name= "Property", metaType = "string", idType = "integer",
+ metaValues = {
+ @MetaValue(value = "C", targetEntity = CharProperty.class),
+ @MetaValue(value = "I", targetEntity = IntegerProperty.class),
+ @MetaValue(value = "S", targetEntity = StringProperty.class),
+ @MetaValue(value = "L", targetEntity = LongProperty.class)
+ })
+)
+
+package org.hibernate.test.annotations.any;
+
+import org.hibernate.annotations.AnyMetaDefs;
+import org.hibernate.annotations.AnyMetaDef;
+import org.hibernate.annotations.MetaValue;
\ No newline at end of file
More information about the hibernate-commits
mailing list