[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