Author: epbernard Date: 2006-04-18 23:37:31 -0400 (Tue, 18 Apr 2006) New Revision: 9768 Added: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Atmosphere.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Gas.java Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/MapBinder.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/collectionelement/Boy.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/collectionelement/CollectionElementTest.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java Log: ANN-1 <Element, Element>, <Element, @Component> <Element, Entity> work Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/MapBinder.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/MapBinder.java 2006-04-19 02:50:37 UTC (rev 9767) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/MapBinder.java 2006-04-19 03:37:31 UTC (rev 9768) @@ -3,17 +3,29 @@ import java.util.Iterator; import java.util.Map; +import java.util.HashMap; +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.Embeddable; + import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.FetchMode; import org.hibernate.MappingException; +import org.hibernate.annotations.AccessType; import org.hibernate.cfg.BinderHelper; import org.hibernate.cfg.CollectionSecondPass; import org.hibernate.cfg.Ejb3Column; import org.hibernate.cfg.Ejb3JoinColumn; import org.hibernate.cfg.ExtendedMappings; import org.hibernate.cfg.SecondPass; +import org.hibernate.cfg.AnnotatedClassType; +import org.hibernate.cfg.PropertyHolder; +import org.hibernate.cfg.PropertyHolderBuilder; +import org.hibernate.cfg.PropertyData; +import org.hibernate.cfg.PropertyPreloadedData; +import org.hibernate.cfg.AnnotationBinder; import org.hibernate.mapping.Collection; import org.hibernate.mapping.Column; import org.hibernate.mapping.Component; @@ -22,7 +34,12 @@ import org.hibernate.mapping.Property; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Value; +import org.hibernate.mapping.ManyToOne; +import org.hibernate.mapping.Join; import org.hibernate.reflection.XProperty; +import org.hibernate.reflection.XClass; +import org.hibernate.reflection.ReflectionManager; +import org.hibernate.reflection.XAnnotatedElement; /** * Implementation to bind a Map @@ -52,26 +69,142 @@ persistentClasses, collType, fkJoinColumns, keyColumns, inverseColumns, elementColumns, isEmbedded, property, fetchMode, unique, assocTableBinder, ignoreNotFound, mappings ); - bindKeyFromAssociationTable( collType, persistentClasses, mapKeyPropertyName, mappings ); + bindKeyFromAssociationTable( collType, persistentClasses, mapKeyPropertyName, property, ignoreNotFound, isEmbedded, mappings ); } }; } private void bindKeyFromAssociationTable( - String collType, Map persistentClasses, String mapKeyPropertyName, ExtendedMappings mappings + String collType, Map persistentClasses, String mapKeyPropertyName, XProperty property, boolean ignoreNotFound, boolean isEmbedded, ExtendedMappings mappings ) { - if ( mapKeyPropertyName == null ) throw new AnnotationException( "A Map must declare a @MapKey element" ); - PersistentClass associatedClass = (PersistentClass) persistentClasses.get( collType ); - if ( associatedClass == null ) throw new AnnotationException( "Associated class not found: " + collType ); - Property property = BinderHelper.findPropertyByName( associatedClass, mapKeyPropertyName ); - if ( property == null ) { - throw new AnnotationException( - "Map key property not found: " + collType + "." + mapKeyPropertyName - ); + if ( mapKeyPropertyName != null ) { + PersistentClass associatedClass = (PersistentClass) persistentClasses.get( collType ); + if ( associatedClass == null ) throw new AnnotationException( "Associated class not found: " + collType ); + Property mapProperty = BinderHelper.findPropertyByName( associatedClass, mapKeyPropertyName ); + if ( mapProperty == null ) { + throw new AnnotationException( + "Map key property not found: " + collType + "." + mapKeyPropertyName + ); + } + org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection; + Value indexValue = createFormulatedValue( mapProperty.getValue(), map ); + map.setIndex( indexValue ); } - org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection; - Value indexValue = createFormulatedValue( property.getValue(), map ); - map.setIndex( indexValue ); + else { + //throw new AnnotationException( "A Map must declare a @MapKey element" ); + //TODO ugly copy/pastle from CollectionBinder.bindManyToManySecondPass + String mapKeyType = property.getMapKey().getName(); + PersistentClass collectionEntity = (PersistentClass) persistentClasses.get( mapKeyType ); + boolean isCollectionOfEntities = collectionEntity != null; + ManyToOne element = null; + org.hibernate.mapping.Map mapValue = (org.hibernate.mapping.Map) this.collection; + if ( isCollectionOfEntities ) { + element = + new ManyToOne( mapValue.getCollectionTable() ); + mapValue.setIndex( element ); + element.setReferencedEntityName( mapKeyType ); + //element.setFetchMode( fetchMode ); + //element.setLazy( fetchMode != FetchMode.JOIN ); + //make the second join non lazy + element.setFetchMode( FetchMode.JOIN ); + element.setLazy( false ); + element.setIgnoreNotFound( ignoreNotFound ); + } + else { + XClass elementClass; + AnnotatedClassType classType; + // Map<String, javax.persistence.Column[]> columnOverrides = PropertyHolderBuilder.buildColumnOverride( + // property, StringHelper.qualify( collValue.getRole(), "element" ) + // ); + //FIXME the "element" is lost + PropertyHolder holder = null; + if ( BinderHelper.PRIMITIVE_NAMES.contains( mapKeyType ) ) { + classType = AnnotatedClassType.NONE; + elementClass = null; + } + else { + try { + elementClass = ReflectionManager.INSTANCE.classForName( mapKeyType, MapBinder.class ); + } + catch (ClassNotFoundException e) { + throw new AnnotationException( "Unable to find class: " + mapKeyType, e ); + } + classType = mappings.getClassType( elementClass ); + + holder = PropertyHolderBuilder.buildPropertyHolder( + mapValue, + mapValue.getRole(), + elementClass, + property + ); + //force in case of attribute override + boolean attributeOverride = property.isAnnotationPresent( AttributeOverride.class) + || property.isAnnotationPresent( AttributeOverrides.class); + if ( isEmbedded || attributeOverride ) { + classType = AnnotatedClassType.EMBEDDABLE; + } + } + + if ( AnnotatedClassType.EMBEDDABLE.equals( classType ) ) { + EntityBinder entityBinder = new EntityBinder(); + Embeddable embeddable = (Embeddable) elementClass.getAnnotation( Embeddable.class ); + PersistentClass owner = mapValue.getOwner(); + boolean isPropertyAnnotated; + AccessType access = ( (XAnnotatedElement) elementClass).getAnnotation( AccessType.class ); + //FIXME support @Access for collection of elements + //String accessType = access != null ? access.value() : null; + if ( owner.getIdentifierProperty() != null) { + isPropertyAnnotated = owner.getIdentifierProperty().getPropertyAccessorName().equals( "property" ); + } + else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().getPropertySpan() > 0 ) { + Property prop = (Property) owner.getIdentifierMapper().getPropertyIterator().next(); + isPropertyAnnotated = prop.getPropertyAccessorName().equals("property"); + } + else { + throw new AssertionFailure( "Unable to guess collection property accessor name" ); + } + + //boolean propertyAccess = embeddable == null || AccessType.PROPERTY.equals( embeddable.access() ); + //FIXME "index" is it right? + PropertyData inferredData = new PropertyPreloadedData( "property", "index", elementClass ); + //TODO be smart with isNullable + Component component = AnnotationBinder.fillComponent( + holder, inferredData, isPropertyAnnotated, isPropertyAnnotated ? "property" : "field", true, + entityBinder, false, false, + mappings + ); + mapValue.setIndex( component ); + } + else { + SimpleValueBinder elementBinder = new SimpleValueBinder(); + elementBinder.setMappings( mappings ); + elementBinder.setReturnedClassName( mapKeyType ); + //FIXME get the columns from an annotation + Ejb3Column[] elementColumns = null; + if ( elementColumns == null || elementColumns.length == 0 ) { + elementColumns = new Ejb3Column[1]; + Ejb3Column column = new Ejb3Column(); + column.setImplicit( false ); + column.setNullable( false ); + column.setLength( Ejb3Column.DEFAULT_COLUMN_LENGTH ); + column.setLogicalColumnName( Collection.DEFAULT_KEY_COLUMN_NAME ); //TODO inject column name here + //TODO create an EMPTY_JOINS collection + column.setJoins( new HashMap<String, Join>() ); + column.setMappings( mappings ); + column.bind(); + elementColumns[0] = column; + } + //override the table + for ( Ejb3Column column : elementColumns ) { + column.setTable( mapValue.getCollectionTable() ); + } + elementBinder.setColumns( elementColumns ); + elementBinder.setType( property, elementClass ); + mapValue.setIndex( elementBinder.make() ); + } + } + + } } protected Value createFormulatedValue(Value value, Collection collection) { Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/collectionelement/Boy.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/collectionelement/Boy.java 2006-04-19 02:50:37 UTC (rev 9767) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/collectionelement/Boy.java 2006-04-19 03:37:31 UTC (rev 9768) @@ -3,6 +3,8 @@ import java.util.HashSet; import java.util.Set; +import java.util.Map; +import java.util.HashMap; import javax.persistence.AttributeOverride; import javax.persistence.Column; import javax.persistence.Entity; @@ -25,6 +27,7 @@ private String firstName; private String lastName; private Set<String> nickNames = new HashSet<String>(); + private Map<String, Integer> scorePerNickName = new HashMap<String, Integer>(); private int[] favoriteNumbers; private Set<Toy> favoriteToys = new HashSet<Toy>(); private Set<Character> characters = new HashSet<Character>(); @@ -65,6 +68,17 @@ } @CollectionOfElements + @JoinTable(name="ScorePerNickName", joinColumns = @JoinColumn(name = "BoyId") ) + @Column(name="score", nullable = false) + public Map<String, Integer> getScorePerNickName() { + return scorePerNickName; + } + + public void setScorePerNickName(Map<String, Integer> scorePerNickName) { + this.scorePerNickName = scorePerNickName; + } + + @CollectionOfElements @JoinTable( name="BoyFavoriteNumbers", joinColumns = @JoinColumn(name="BoyId") Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/collectionelement/CollectionElementTest.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/collectionelement/CollectionElementTest.java 2006-04-19 02:50:37 UTC (rev 9767) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/collectionelement/CollectionElementTest.java 2006-04-19 03:37:31 UTC (rev 9768) @@ -19,6 +19,8 @@ boy.setLastName( "Doe" ); boy.getNickNames().add("Johnny"); boy.getNickNames().add("Thing"); + boy.getScorePerNickName().put( "Johnny", new Integer(3) ) ; + boy.getScorePerNickName().put( "Thing", new Integer(5) ) ; int[] favNbrs = new int[4]; for (int index = 0 ; index < favNbrs.length - 1 ; index++) { favNbrs[index] = index * 3; @@ -33,6 +35,9 @@ boy = (Boy) s.get( Boy.class, boy.getId() ); assertNotNull( boy.getNickNames() ); assertTrue( boy.getNickNames().contains( "Thing" ) ); + assertNotNull( boy.getScorePerNickName() ); + assertTrue( boy.getScorePerNickName().containsKey( "Thing" ) ); + assertEquals( new Integer(5), boy.getScorePerNickName().get("Thing") ); assertNotNull( boy.getFavoriteNumbers() ); assertEquals( 3, boy.getFavoriteNumbers()[1] ); assertTrue( boy.getCharacters().contains( Character.CRAFTY ) ); @@ -95,6 +100,8 @@ } + + protected Class[] getMappings() { return new Class[] { Boy.class, Added: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Atmosphere.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Atmosphere.java 2006-04-19 02:50:37 UTC (rev 9767) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Atmosphere.java 2006-04-19 03:37:31 UTC (rev 9768) @@ -0,0 +1,20 @@ +//$Id: $ +package org.hibernate.test.annotations.indexcoll; + +import java.util.HashMap; +import java.util.Map; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToMany; + +/** + * @author Emmanuel Bernard + */ +@Entity +public class Atmosphere { + @Id @GeneratedValue public Integer id; + @ManyToMany(cascade = CascadeType.ALL) + public Map<String, Gas> gases = new HashMap<String, Gas>(); +} Added: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Gas.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Gas.java 2006-04-19 02:50:37 UTC (rev 9767) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Gas.java 2006-04-19 03:37:31 UTC (rev 9768) @@ -0,0 +1,16 @@ +//$Id: $ +package org.hibernate.test.annotations.indexcoll; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.GeneratedValue; + +/** + * @author Emmanuel Bernard + */ +@Entity +public class Gas { + @Id @GeneratedValue public Integer id; + public String name; + +} Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java 2006-04-19 02:50:37 UTC (rev 9767) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java 2006-04-19 03:37:31 UTC (rev 9768) @@ -323,6 +323,27 @@ s.close(); } + public void testRealMap() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + Atmosphere atm = new Atmosphere(); + Gas o2 = new Gas(); + o2.name = "oxygen"; + atm.gases.put( "100%", o2 ); + s.persist( atm ); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + atm = (Atmosphere) s.get(Atmosphere.class, atm.id); + assertEquals( 1, atm.gases.size() ); + assertEquals( o2.name, atm.gases.get("100%").name ); + s.delete( atm ); + tx.commit(); + s.close(); + } + public IndexedCollectionTest(String x) { super( x ); } @@ -341,7 +362,9 @@ News.class, PressReleaseAgency.class, Painter.class, - Painting.class + Painting.class, + Atmosphere.class, + Gas.class }; } } |