From 2a525be55068fda9cdc019e3635182fa22d4be99 Mon Sep 17 00:00:00 2001 From: Graeme Rocher Date: Thu, 24 Mar 2011 10:09:05 +0100 Subject: [PATCH] upgrade to Hibernate 3.6 --- build.gradle | 3 +- grails-hibernate/build.gradle | 8 +- .../grails/orm/HibernateCriteriaBuilder.java | 15 +- .../cfg/GrailsAnnotationConfiguration.java | 28 +-- .../orm/hibernate/cfg/GrailsDomainBinder.java | 180 ++++++------------ .../orm/hibernate/cfg/IdentityEnumType.java | 41 ++-- .../GroovyAwareJavassistLazyInitializer.java | 1 + .../GroovyAwareJavassistProxyFactory.java | 13 +- .../HibernateDialectDetectorFactoryBean.java | 51 +++-- .../orm/hibernate/MappingDslTests.groovy | 33 ++-- .../PackagedCustomMappingTests.groovy | 11 +- .../orm/hibernate/SessionFactoryAdapter.java | 16 +- 12 files changed, 187 insertions(+), 213 deletions(-) diff --git a/build.gradle b/build.gradle index f4868640ecb..187cc7c1d36 100644 --- a/build.gradle +++ b/build.gradle @@ -69,6 +69,7 @@ subprojects { project -> mavenCentral() mavenRepo urls:"http://maven.springframework.org/release" mavenRepo urls:'http://maven.springframework.org/snapshot' + mavenRepo name:'jboss-public', urls:'http://repository.jboss.org/nexus/content/groups/public-jboss/' } dependencies { // Groovy @@ -114,7 +115,7 @@ subprojects { project -> // Specs compile 'javax.servlet:servlet-api:2.5' compile 'javax.transaction:jta:1.1' - compile 'javax.persistence:persistence-api:1.0' + compile 'org.hibernate.java-persistence:jpa-api:2.0-cr-1' // Spring diff --git a/grails-hibernate/build.gradle b/grails-hibernate/build.gradle index d960702d949..158d6d3fd4c 100644 --- a/grails-hibernate/build.gradle +++ b/grails-hibernate/build.gradle @@ -12,15 +12,13 @@ dependencies { } // Hibernate related - compile 'org.hibernate:hibernate-annotations:3.4.0.GA', - 'org.hibernate:hibernate-commons-annotations:3.1.0.GA', - 'org.hibernate:hibernate-core:3.3.1.GA' + compile 'org.hibernate:hibernate-core:3.6.1.Final' compile 'javassist:javassist:3.11.0.GA' - runtime 'org.hibernate:hibernate-validator:3.1.0.GA', - 'org.hibernate:hibernate-ehcache:3.3.1.GA', + runtime 'org.hibernate:hibernate-validator:4.1.0.Final', + 'org.hibernate:hibernate-ehcache:3.6.1.Final', 'antlr:antlr:2.7.6' diff --git a/grails-hibernate/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java b/grails-hibernate/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java index 379e2360dd0..f46e283fb59 100644 --- a/grails-hibernate/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java +++ b/grails-hibernate/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java @@ -1119,13 +1119,13 @@ else if (paginationEnabledList) { criteria.setFirstResult(0); criteria.setMaxResults(Integer.MAX_VALUE); criteria.setProjection(Projections.rowCount()); - int totalCount = ((Integer)criteria.uniqueResult()).intValue(); + int totalCount = ((Number)criteria.uniqueResult()).intValue(); // Drop the projection, add settings for the pagination parameters, // and then execute the query. criteria.setProjection(null); - for (Iterator it = orderEntries.iterator(); it.hasNext();) { - criteria.addOrder(it.next()); + for (Order orderEntry : orderEntries) { + criteria.addOrder(orderEntry); } if (resultTransformer == null) { criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY); @@ -1200,9 +1200,9 @@ else if (paginationEnabledList) { return name; } - if (targetBean.isReadableProperty(name.toString())) { + if (targetBean.isReadableProperty(name)) { ClassMetadata meta = sessionFactory.getClassMetadata(targetBean.getWrappedClass()); - Type type = meta.getPropertyType(name.toString()); + Type type = meta.getPropertyType(name); if (type.isAssociationType()) { String otherSideEntityName = ((AssociationType) type).getAssociatedEntityName((SessionFactoryImplementor) sessionFactory); @@ -1210,7 +1210,7 @@ else if (paginationEnabledList) { targetClass = sessionFactory.getClassMetadata(otherSideEntityName).getMappedClass(EntityMode.POJO); BeanWrapper oldTargetBean = targetBean; targetBean = new BeanWrapperImpl(BeanUtils.instantiateClass(targetClass)); - associationStack.add(name.toString()); + associationStack.add(name); final String associationPath = getAssociationPath(); createAliasIfNeccessary(name, associationPath); // the criteria within an association node are grouped with an implicit AND @@ -1306,8 +1306,7 @@ private String getAssociationPath() { if (fullPath.length() > 0) fullPath.append("."); fullPath.append(propertyName); } - final String associationPath = fullPath.toString(); - return associationPath; + return fullPath.toString(); } private boolean isCriteriaConstructionMethod(String name, Object[] args) { diff --git a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java index 55657027456..68628738844 100644 --- a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java +++ b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java @@ -14,18 +14,9 @@ */ package org.codehaus.groovy.grails.orm.hibernate.cfg; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.codehaus.groovy.grails.commons.AnnotationDomainClassArtefactHandler; -import org.codehaus.groovy.grails.commons.ArtefactHandler; -import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler; -import org.codehaus.groovy.grails.commons.GrailsApplication; -import org.codehaus.groovy.grails.commons.GrailsClass; -import org.codehaus.groovy.grails.commons.GrailsDomainClass; +import org.codehaus.groovy.grails.commons.*; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.SessionFactory; @@ -35,6 +26,10 @@ import org.hibernate.cfg.NamingStrategy; import org.hibernate.engine.FilterDefinition; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + /** * Allows configuring Grails' hibernate support to work in conjuntion with Hibernate's annotation * support. @@ -132,6 +127,8 @@ public SessionFactory buildSessionFactory() throws HibernateException { */ @Override protected void secondPassCompile() throws MappingException { + final Thread currentThread = Thread.currentThread(); + final ClassLoader originalContextLoader = currentThread.getContextClassLoader(); if (!configLocked) { if (LOG.isDebugEnabled()) { LOG.debug("[GrailsAnnotationConfiguration] [" + domainClasses.size() + "] Grails domain classes to bind to persistence runtime"); @@ -145,7 +142,7 @@ protected void secondPassCompile() throws MappingException { final String fullClassName = domainClass.getFullName(); String hibernateConfig = fullClassName.replace('.', '/') + ".hbm.xml"; - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + final ClassLoader loader = originalContextLoader; // don't configure Hibernate mapped classes if (loader.getResource(hibernateConfig) != null) continue; @@ -159,7 +156,14 @@ protected void secondPassCompile() throws MappingException { } } - super.secondPassCompile(); + + try { + currentThread.setContextClassLoader(grailsApplication.getClassLoader()); + super.secondPassCompile(); + } finally { + currentThread.setContextClassLoader(originalContextLoader); + + } configLocked = true; } diff --git a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java index 8c0bafd0f2d..845c10e3fb9 100644 --- a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java +++ b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java @@ -16,20 +16,6 @@ import grails.util.GrailsUtil; import groovy.lang.Closure; - -import java.sql.Types; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.SortedSet; - import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; @@ -45,7 +31,6 @@ import org.codehaus.groovy.grails.plugins.orm.hibernate.HibernatePluginSupport; import org.codehaus.groovy.grails.validation.ConstrainedProperty; import org.hibernate.FetchMode; -import org.hibernate.Hibernate; import org.hibernate.MappingException; import org.hibernate.cfg.ImprovedNamingStrategy; import org.hibernate.cfg.Mappings; @@ -53,15 +38,17 @@ import org.hibernate.cfg.SecondPass; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.mapping.*; +import org.hibernate.mapping.Collection; import org.hibernate.mapping.Table; -import org.hibernate.type.ForeignKeyDirection; -import org.hibernate.type.IntegerType; -import org.hibernate.type.LongType; -import org.hibernate.type.TimestampType; -import org.hibernate.type.Type; -import org.hibernate.type.TypeFactory; +import org.hibernate.type.*; import org.hibernate.util.StringHelper; +import java.sql.Types; +import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** * Handles the binding Grails domain classes and properties to the Hibernate runtime meta model. * Based on the HbmBinder code in Hibernate core and influenced by AnnotationsBinder. @@ -117,7 +104,7 @@ public String toString() { private static CollectionType SET = new CollectionType(Set.class) { @Override public Collection create(GrailsDomainClassProperty property, PersistentClass owner, String path, Mappings mappings) throws MappingException { - org.hibernate.mapping.Set coll = new org.hibernate.mapping.Set(owner); + org.hibernate.mapping.Set coll = new org.hibernate.mapping.Set(mappings, owner); coll.setCollectionTable(owner.getTable()); bindCollection(property, coll, owner, mappings, path); return coll; @@ -127,7 +114,7 @@ public Collection create(GrailsDomainClassProperty property, PersistentClass own private static CollectionType LIST = new CollectionType(List.class) { @Override public Collection create(GrailsDomainClassProperty property, PersistentClass owner, String path, Mappings mappings) throws MappingException { - org.hibernate.mapping.List coll = new org.hibernate.mapping.List(owner); + org.hibernate.mapping.List coll = new org.hibernate.mapping.List(mappings, owner); coll.setCollectionTable(owner.getTable()); bindCollection(property, coll, owner, mappings, path); return coll; @@ -137,7 +124,7 @@ public Collection create(GrailsDomainClassProperty property, PersistentClass own private static CollectionType MAP = new CollectionType(Map.class) { @Override public Collection create(GrailsDomainClassProperty property, PersistentClass owner, String path, Mappings mappings) throws MappingException { - org.hibernate.mapping.Map map = new org.hibernate.mapping.Map(owner); + org.hibernate.mapping.Map map = new org.hibernate.mapping.Map(mappings, owner); bindCollection(property, map, owner, mappings, path); return map; } @@ -276,7 +263,7 @@ private static void bindMapSecondPass(GrailsDomainClassProperty property, Mappin Map persistentClasses, org.hibernate.mapping.Map map) { bindCollectionSecondPass(property, mappings, persistentClasses, map); - SimpleValue value = new SimpleValue(map.getCollectionTable()); + SimpleValue value = new SimpleValue(mappings, map.getCollectionTable()); bindSimpleValue(getIndexColumnType(property, STRING_TYPE), value, true, getIndexColumnName(property),mappings); PropertyConfig pc = getPropertyConfig(property); @@ -291,7 +278,7 @@ private static void bindMapSecondPass(GrailsDomainClassProperty property, Mappin map.setIndex(value); if (!property.isOneToMany() && !property.isManyToMany()) { - SimpleValue elt = new SimpleValue(map.getCollectionTable()); + SimpleValue elt = new SimpleValue(mappings, map.getCollectionTable()); map.setElement(elt); String typeName = getTypeName(property,getPropertyConfig(property), getMapping(property.getDomainClass())); @@ -300,7 +287,7 @@ private static void bindMapSecondPass(GrailsDomainClassProperty property, Mappin typeName = property.getReferencedPropertyType().getName(); } else { - typeName = Hibernate.STRING.getName(); + typeName = StandardBasicTypes.STRING.getName(); } } bindSimpleValue(typeName, elt, false, getMapElementName(property),mappings); @@ -330,7 +317,7 @@ private static void bindListSecondPass(GrailsDomainClassProperty property, Mappi String columnName = getIndexColumnName(property); - SimpleValue iv = new SimpleValue(list.getCollectionTable()); + SimpleValue iv = new SimpleValue(mappings, list.getCollectionTable()); bindSimpleValue("integer", iv, true, columnName, mappings); iv.setTypeName("integer"); list.setIndex(iv); @@ -473,7 +460,7 @@ private static void bindCollectionSecondPass(GrailsDomainClassProperty property, } // setup the primary key references - DependantValue key = createPrimaryKeyValue(property, collection, persistentClasses); + DependantValue key = createPrimaryKeyValue(mappings, property, collection, persistentClasses); // link a bidirectional relationship if (property.isBidirectional()) { @@ -507,7 +494,7 @@ private static void bindCollectionSecondPass(GrailsDomainClassProperty property, if (property.isBidirectional()) { if (LOG.isDebugEnabled()) LOG.debug("[GrailsDomainBinder] Mapping other side " + otherSide.getDomainClass().getName() + "." + otherSide.getName() + " -> " + collection.getCollectionTable().getName() + " as ManyToOne"); - ManyToOne element = new ManyToOne(collection.getCollectionTable()); + ManyToOne element = new ManyToOne(mappings, collection.getCollectionTable()); bindManyToMany(otherSide, element, mappings); collection.setElement(element); bindCollectionForPropertyConfig(collection, propConfig); @@ -572,11 +559,11 @@ private static void bindCollectionWithJoinTable(GrailsDomainClassProperty proper SimpleValue element; if (property.isBasicCollectionType()) { - element = new SimpleValue(collection.getCollectionTable()); + element = new SimpleValue(mappings, collection.getCollectionTable()); } else { // for a normal unidirectional one-to-many we use a join column - element = new ManyToOne(collection.getCollectionTable()); + element = new ManyToOne(mappings, collection.getCollectionTable()); bindUnidirectionalOneToManyInverseValues(property, (ManyToOne) element); } collection.setInverse(false); @@ -604,7 +591,7 @@ private static void bindCollectionWithJoinTable(GrailsDomainClassProperty proper String typeName = getTypeName(property, config, getMapping(property.getDomainClass())); if (typeName == null) { - Type type = TypeFactory.basic(className); + Type type = mappings.getTypeResolver().basic(className); if (type != null) { typeName = type.getName(); } @@ -759,13 +746,15 @@ private static void bindDependentKeyValue(GrailsDomainClassProperty property, De /** * Creates the DependentValue object that forms a primary key reference for the collection * + * + * @param mappings * @param property The grails property * @param collection The collection object * @param persistentClasses * @return The DependantValue (key) */ - private static DependantValue createPrimaryKeyValue(@SuppressWarnings("unused") GrailsDomainClassProperty property, - Collection collection, @SuppressWarnings("unused") Map persistentClasses) { + private static DependantValue createPrimaryKeyValue(Mappings mappings, @SuppressWarnings("unused") GrailsDomainClassProperty property, + Collection collection, @SuppressWarnings("unused") Map persistentClasses) { KeyValue keyValue; DependantValue key; String propertyRef = collection.getReferencedPropertyName(); @@ -779,7 +768,7 @@ private static DependantValue createPrimaryKeyValue(@SuppressWarnings("unused") if (LOG.isDebugEnabled()) LOG.debug("[GrailsDomainBinder] creating dependant key value to table [" + keyValue.getTable().getName() + "]"); - key = new DependantValue(collection.getCollectionTable(), keyValue); + key = new DependantValue(mappings, collection.getCollectionTable(), keyValue); key.setTypeName(null); // make nullable and non-updateable @@ -919,7 +908,7 @@ else if (pc != null && pc.getFetch() != null) { // if it's a one-to-many mapping if (shouldBindCollectionWithForeignKey(property)) { - OneToMany oneToMany = new OneToMany(collection.getOwner()); + OneToMany oneToMany = new OneToMany(mappings, collection.getOwner()); collection.setElement(oneToMany); bindOneToMany(property, oneToMany, mappings); } else { @@ -1205,8 +1194,7 @@ public static void bindRoot(GrailsDomainClass domainClass, Mappings mappings) { private static void bindSubClasses(GrailsDomainClass domainClass, PersistentClass parent, Mappings mappings) { Set subClasses = domainClass.getSubClasses(); - for (Iterator i = subClasses.iterator(); i.hasNext();) { - GrailsDomainClass sub = i.next(); + for (GrailsDomainClass sub : subClasses) { if (sub.getClazz().getSuperclass().equals(domainClass.getClazz())) { bindSubClass(sub, parent, mappings); } @@ -1280,7 +1268,7 @@ private static void bindJoinedSubClass(GrailsDomainClass sub, JoinedSubclass joi LOG.info("Mapping joined-subclass: " + joinedSubclass.getEntityName() + " -> " + joinedSubclass.getTable().getName()); - SimpleValue key = new DependantValue(mytable, joinedSubclass.getIdentifier()); + SimpleValue key = new DependantValue(mappings, mytable, joinedSubclass.getIdentifier()); joinedSubclass.setKey(key); GrailsDomainClassProperty identifier = sub.getIdentifier(); String columnName = getColumnNameForPropertyAndPath(identifier, EMPTY_PATH, null); @@ -1304,7 +1292,7 @@ private static String getJoinedSubClassTableName( } /** - * Binds a sub-class using table-per-heirarchy in heritance mapping + * Binds a sub-class using table-per-hierarchy inheritance mapping * * @param sub The Grails domain class instance representing the sub-class * @param subClass The Hibernate SubClass instance @@ -1328,7 +1316,7 @@ private static void bindSubClass(GrailsDomainClass sub, Subclass subClass, Mappi } /** - * Creates and binds the discriminator property used in table-per-heirarchy inheritance to + * Creates and binds the discriminator property used in table-per-hierarchy inheritance to * discriminate between sub class instances * * @param table The table to bind onto @@ -1337,7 +1325,7 @@ private static void bindSubClass(GrailsDomainClass sub, Subclass subClass, Mappi */ private static void bindDiscriminatorProperty(Table table, RootClass entity, Mappings mappings) { Mapping m = getMapping(entity.getMappedClass()); - SimpleValue d = new SimpleValue(table); + SimpleValue d = new SimpleValue(mappings, table); entity.setDiscriminator(d); entity.setDiscriminatorValue(m!=null && m.getDiscriminator() != null ? m.getDiscriminator() : entity.getClassName()); @@ -1378,12 +1366,8 @@ private static void configureDerivedProperties(GrailsDomainClass domainClass, Ma } } - /** + /* * Binds a persistent classes to the table representation and binds the class properties - * - * @param domainClass - * @param root - * @param mappings */ private static void bindRootPersistentClassCommonValues(GrailsDomainClass domainClass, RootClass root, Mappings mappings) { @@ -1398,12 +1382,15 @@ private static void bindRootPersistentClassCommonValues(GrailsDomainClass domain CacheConfig cc = m.getCache(); if (cc != null && cc.getEnabled()) { root.setCacheConcurrencyStrategy(cc.getUsage()); + if("read-only".equals(cc.getUsage())) { + root.setMutable(false); + } root.setLazyPropertiesCacheable(!"non-lazy".equals(cc.getInclude())); } Integer bs = m.getBatchSize(); if (bs != null) { - root.setBatchSize(bs.intValue()); + root.setBatchSize(bs); } if (m.getDynamicUpdate()) { @@ -1478,7 +1465,7 @@ private static void bindIdentity(GrailsDomainClass domainClass, RootClass root, } private static void bindCompositeId(GrailsDomainClass domainClass, RootClass root, CompositeIdentity compositeIdentity, Mappings mappings) { - Component id = new Component(root); + Component id = new Component(mappings, root); id.setNullValue("undefined"); root.setIdentifier(id); root.setEmbeddedIdentifier(true); @@ -1502,7 +1489,7 @@ private static void bindCompositeId(GrailsDomainClass domainClass, RootClass roo } /** - * Creates and binds the properties for the specified Grails domain class and PersistantClass + * Creates and binds the properties for the specified Grails domain class and PersistentClass * and binds them to the Hibernate runtime meta model * * @param domainClass The Grails domain class @@ -1544,7 +1531,7 @@ protected static void createClassProperties(GrailsDomainClass domainClass, Persi value = collection; } else if (currentGrailsProp.isEnum()) { - value = new SimpleValue(table); + value = new SimpleValue(mappings, table); bindEnumType(currentGrailsProp, (SimpleValue) value, EMPTY_PATH); } // work out what type of relationship it is and bind value @@ -1552,7 +1539,7 @@ else if (currentGrailsProp.isManyToOne()) { if (LOG.isDebugEnabled()) LOG.debug("[GrailsDomainBinder] Binding property [" + currentGrailsProp.getName() + "] as ManyToOne"); - value = new ManyToOne(table); + value = new ManyToOne(mappings, table); bindManyToOne(currentGrailsProp, (ManyToOne) value, EMPTY_PATH, mappings); } else if (currentGrailsProp.isOneToOne() && userType == null) { @@ -1564,22 +1551,22 @@ else if (currentGrailsProp.isOneToOne() && userType == null) { "." + currentGrailsProp.getName() + "] is not bidirectional. Specify the other side of the relationship!"); } else if (canBindOneToOneWithSingleColumnAndForeignKey(currentGrailsProp)) { - value = new OneToOne(table, persistentClass); + value = new OneToOne(mappings, table, persistentClass); bindOneToOne(currentGrailsProp, (OneToOne) value, EMPTY_PATH); } else { if (currentGrailsProp.isHasOne() && currentGrailsProp.isBidirectional()) { - value = new OneToOne(table, persistentClass); + value = new OneToOne(mappings, table, persistentClass); bindOneToOne(currentGrailsProp, (OneToOne) value, EMPTY_PATH); } else { - value = new ManyToOne(table); + value = new ManyToOne(mappings, table); bindManyToOne(currentGrailsProp, (ManyToOne) value, EMPTY_PATH, mappings); } } } else if (currentGrailsProp.isEmbedded()) { - value = new Component(persistentClass); + value = new Component(mappings, persistentClass); bindComponent((Component) value, currentGrailsProp, true, mappings); } @@ -1587,7 +1574,7 @@ else if (currentGrailsProp.isEmbedded()) { if (LOG.isDebugEnabled()) LOG.debug("[GrailsDomainBinder] Binding property [" + currentGrailsProp.getName() + "] as SimpleValue"); - value = new SimpleValue(table); + value = new SimpleValue(mappings, table); bindSimpleValue(currentGrailsProp, null, (SimpleValue) value, EMPTY_PATH, mappings); } @@ -1630,7 +1617,7 @@ private static boolean canBindOneToOneWithSingleColumnAndForeignKey(GrailsDomain if (currentGrailsProp.isBidirectional()) { final GrailsDomainClassProperty otherSide = currentGrailsProp.getOtherSide(); if (otherSide.isHasOne()) return false; - if (!currentGrailsProp.isOwningSide() && (otherSide != null && otherSide.isOwningSide())) { + if (!currentGrailsProp.isOwningSide() && (otherSide.isOwningSide())) { return true; } } @@ -1779,7 +1766,7 @@ private static void bindComponent(Component component, GrailsDomainClassProperty private static void bindComponentProperty(Component component, GrailsDomainClassProperty componentProperty, GrailsDomainClassProperty currentGrailsProp, PersistentClass persistentClass, String path, Table table, Mappings mappings) { - Value value = null; + Value value; // see if its a collection type CollectionType collectionType = CollectionType.collectionTypeForClass(currentGrailsProp.getType()); if (collectionType != null) { @@ -1799,30 +1786,30 @@ else if (currentGrailsProp.isManyToOne()) { if (LOG.isDebugEnabled()) LOG.debug("[GrailsDomainBinder] Binding property [" + currentGrailsProp.getName() + "] as ManyToOne"); - value = new ManyToOne(table); + value = new ManyToOne(mappings, table); bindManyToOne(currentGrailsProp, (ManyToOne) value, path, mappings); } else if (currentGrailsProp.isOneToOne()) { if (LOG.isDebugEnabled()) LOG.debug("[GrailsDomainBinder] Binding property [" + currentGrailsProp.getName() + "] as OneToOne"); if (canBindOneToOneWithSingleColumnAndForeignKey(currentGrailsProp)) { - value = new OneToOne(table, persistentClass); + value = new OneToOne(mappings, table, persistentClass); bindOneToOne(currentGrailsProp, (OneToOne) value, path); } else { - value = new ManyToOne(table); + value = new ManyToOne(mappings, table); bindManyToOne(currentGrailsProp, (ManyToOne) value, path, mappings); } } else if (currentGrailsProp.isEmbedded()) { - value = new Component(persistentClass); + value = new Component(mappings, persistentClass); bindComponent((Component) value, currentGrailsProp, true, mappings); } else { if (LOG.isDebugEnabled()) LOG.debug("[GrailsDomainBinder] Binding property [" + currentGrailsProp.getName() + "] as SimpleValue"); - value = new SimpleValue(table); + value = new SimpleValue(mappings, table); if (currentGrailsProp.isEnum()) { bindEnumType(currentGrailsProp, (SimpleValue) value, path); } @@ -1851,12 +1838,9 @@ private static boolean isComponentPropertyNullable(GrailsDomainClassProperty com return !domainClass.isRoot() && (mapping == null || mapping.isTablePerHierarchy()) || componentProperty.isOptional(); } - /** - * Creates a persistant class property based on the GrailDomainClassProperty instance + /* + * Creates a persistent class property based on the GrailDomainClassProperty instance * - * @param value - * @param persistentClass - * @param mappings */ private static Property createProperty(Value value, PersistentClass persistentClass, GrailsDomainClassProperty grailsProperty, Mappings mappings) { // set type @@ -1872,35 +1856,7 @@ private static Property createProperty(Value value, PersistentClass persistentCl return prop; } - /** - * @param property - * @param oneToOne - * @param mappings - */ -/* private static void bindOneToOne(GrailsDomainClassProperty property, OneToOne oneToOne, Mappings mappings) { - - // bind value - bindSimpleValue(property, oneToOne, mappings ); - // set foreign key type - oneToOne.setForeignKeyType( ForeignKeyDirection.FOREIGN_KEY_TO_PARENT ); - - oneToOne.setForeignKeyName( property.getFieldName() + FOREIGN_KEY_SUFFIX ); - - // TODO configure fetch settings - oneToOne.setFetchMode( FetchMode.DEFAULT ); - // TODO configure lazy loading - oneToOne.setLazy(true); - - oneToOne.setPropertyName( property.getTagName() ); - oneToOne.setReferencedEntityName( property.getType().getTagName() ); - - - }*/ - - /** - * @param currentGrailsProp - * @param one - * @param mappings + /* */ private static void bindOneToMany(GrailsDomainClassProperty currentGrailsProp, OneToMany one, @SuppressWarnings("unused") Mappings mappings) { @@ -1911,10 +1867,6 @@ private static void bindOneToMany(GrailsDomainClassProperty currentGrailsProp, O /** * Binds a many-to-one relationship to the * - * @param property - * @param manyToOne - * @param path - * @param mappings */ @SuppressWarnings("unchecked") private static void bindManyToOne(GrailsDomainClassProperty property, ManyToOne manyToOne, @@ -2018,8 +1970,6 @@ private static void bindOneToOne(final GrailsDomainClassProperty property, OneTo } /** - * @param property - * @param manyToOne */ private static void bindManyToOneValues(GrailsDomainClassProperty property, ManyToOne manyToOne) { PropertyConfig config = getPropertyConfig(property); @@ -2031,7 +1981,7 @@ private static void bindManyToOneValues(GrailsDomainClassProperty property, Many manyToOne.setFetchMode(FetchMode.DEFAULT); } - manyToOne.setLazy(getLazyiness(property)); + manyToOne.setLazy(getLaziness(property)); if (config != null) { manyToOne.setIgnoreNotFound(config.getIgnoreNotFound()); @@ -2042,12 +1992,10 @@ private static void bindManyToOneValues(GrailsDomainClassProperty property, Many } /** - * @param version - * @param mappings */ private static void bindVersion(GrailsDomainClassProperty version, RootClass entity, Mappings mappings) { - SimpleValue val = new SimpleValue(entity.getTable()); + SimpleValue val = new SimpleValue(mappings, entity.getTable()); bindSimpleValue(version, null, val, EMPTY_PATH, mappings); @@ -2072,17 +2020,11 @@ private static void bindVersion(GrailsDomainClassProperty version, RootClass ent entity.addProperty(prop); } - /** - * @param identifier - * @param entity - * @param mappings - * @param mappedId - */ @SuppressWarnings("unchecked") private static void bindSimpleId(GrailsDomainClassProperty identifier, RootClass entity, Mappings mappings, Identity mappedId) { // create the id value - SimpleValue id = new SimpleValue(entity.getTable()); + SimpleValue id = new SimpleValue(mappings, entity.getTable()); // set identifier on entity Properties params = new Properties(); @@ -2100,6 +2042,8 @@ private static void bindSimpleId(GrailsDomainClassProperty identifier, RootClass id.setIdentifierGeneratorStrategy("native"); } + params.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, mappings.getObjectNameNormalizer() ); + if (mappings.getSchemaName() != null) { params.setProperty(PersistentIdentifierGenerator.SCHEMA, mappings.getSchemaName()); } @@ -2153,7 +2097,7 @@ private static void bindProperty(GrailsDomainClassProperty grailsProperty, Prope grailsProperty.isPersistent() && !grailsProperty.isAssociation() && !grailsProperty.isIdentity(); if (isLazyable) { - final boolean isLazy = getLazyiness(grailsProperty); + final boolean isLazy = getLaziness(grailsProperty); prop.setLazy(isLazy); if (isLazy && (grailsProperty.isManyToOne() || grailsProperty.isOneToOne())) { @@ -2162,7 +2106,7 @@ private static void bindProperty(GrailsDomainClassProperty grailsProperty, Prope } } - private static boolean getLazyiness(GrailsDomainClassProperty grailsProperty) { + private static boolean getLaziness(GrailsDomainClassProperty grailsProperty) { PropertyConfig config = getPropertyConfig(grailsProperty); final boolean isLazy = config!=null ? config.getLazy() : true; return isLazy; diff --git a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/IdentityEnumType.java b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/IdentityEnumType.java index 5502c31a6de..94685aac2c3 100644 --- a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/IdentityEnumType.java +++ b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/IdentityEnumType.java @@ -14,30 +14,26 @@ */ package org.codehaus.groovy.grails.orm.hibernate.cfg; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - import grails.util.GrailsWebUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.groovy.grails.commons.GrailsClassUtils; import org.hibernate.HibernateException; import org.hibernate.MappingException; -import org.hibernate.type.NullableType; -import org.hibernate.type.TypeFactory; +import org.hibernate.type.AbstractStandardBasicType; +import org.hibernate.type.TypeResolver; import org.hibernate.usertype.ParameterizedType; import org.hibernate.usertype.UserType; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + /** * Hibernate Usertype that enum values by their ID. * @@ -50,14 +46,15 @@ public class IdentityEnumType implements UserType, ParameterizedType, Serializab private static final Log LOG = LogFactory.getLog(IdentityEnumType.class); + private static TypeResolver typeResolver = new TypeResolver(); public static final String ENUM_ID_ACCESSOR = "getId"; + public static final String PARAM_ENUM_CLASS = "enumClass"; private static final Map>, BidiEnumMap> ENUM_MAPPINGS = new HashMap>, BidiEnumMap>(); - private Class> enumClass; private BidiEnumMap bidiMap; - private NullableType type; + private AbstractStandardBasicType type; private int[] sqlTypes; public static BidiEnumMap getBidiEnumMap(Class> cls) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { @@ -90,7 +87,7 @@ public static boolean supports(@SuppressWarnings("rawtypes") Class enumClass) { int mods = idAccessor.getModifiers(); if (Modifier.isPublic(mods) && !Modifier.isStatic(mods)) { Class returnType = idAccessor.getReturnType(); - return returnType != null && TypeFactory.basic(returnType.getName()) instanceof NullableType; + return returnType != null && typeResolver.basic(returnType.getName()) instanceof AbstractStandardBasicType; } } catch (NoSuchMethodException e) { @@ -109,11 +106,11 @@ public void setParameterValues(Properties properties) { LOG.debug(String.format("Building ID-mapping for Enum Class %s", enumClass.getName())); } bidiMap = getBidiEnumMap(enumClass); - type = (NullableType) TypeFactory.basic(bidiMap.keyType.getName()); + type = (AbstractStandardBasicType)typeResolver.basic(bidiMap.keyType.getName()); if (LOG.isDebugEnabled()) { LOG.debug(String.format("Mapped Basic Type is %s", type)); } - sqlTypes = new int[]{type.sqlType()}; + sqlTypes = type.sqlTypes(null); } catch (Exception e) { throw new MappingException("Error mapping Enum Class using IdentifierEnumType", e); @@ -137,7 +134,7 @@ public int hashCode(Object o) throws HibernateException { } public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException { - Object id = type.get(resultSet, names[0]); + Object id = type.nullSafeGet(resultSet, names[0], null); if ((!resultSet.wasNull()) && id != null) { return bidiMap.getEnumValue(id); } @@ -149,7 +146,7 @@ public void nullSafeSet(PreparedStatement pstmt, Object value, int idx) throws H pstmt.setNull(idx, sqlTypes[0]); } else { - type.set(pstmt, bidiMap.getKey(value), idx); + type.nullSafeSet(pstmt, bidiMap.getKey(value), idx, null); } } diff --git a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwareJavassistLazyInitializer.java b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwareJavassistLazyInitializer.java index c0ba1982d1c..23d1be39e30 100644 --- a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwareJavassistLazyInitializer.java +++ b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwareJavassistLazyInitializer.java @@ -231,6 +231,7 @@ protected Object serializableProxy() { persistentClass, interfaces, getIdentifier(), + false, getIdentifierMethod, setIdentifierMethod, componentIdType diff --git a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwareJavassistProxyFactory.java b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwareJavassistProxyFactory.java index e539f7f1d7e..672f2735dfc 100644 --- a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwareJavassistProxyFactory.java +++ b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwareJavassistProxyFactory.java @@ -14,15 +14,16 @@ */ package org.codehaus.groovy.grails.orm.hibernate.proxy; -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Set; - import org.hibernate.HibernateException; import org.hibernate.engine.SessionImplementor; import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.ProxyFactory; import org.hibernate.type.AbstractComponentType; +import org.hibernate.type.CompositeType; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.Set; /** * Hibernate's default proxying mechanism proxies Groovy's getMetaClass() method. To avoid this @@ -60,6 +61,10 @@ public void postInstantiate( factory = GroovyAwareJavassistLazyInitializer.getProxyFactory(persistentClass, this.interfaces); } + public void postInstantiate(String entityName, Class persistentClass, Set interfaces, Method getIdentifierMethod, Method setIdentifierMethod, CompositeType componentIdType) throws HibernateException { + // do nothing + } + public HibernateProxy getProxy(Serializable id, SessionImplementor session) throws HibernateException { return GroovyAwareJavassistLazyInitializer.getProxy( factory, diff --git a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java index d2a10876593..d4be84026e8 100644 --- a/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java +++ b/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java @@ -15,30 +15,34 @@ */ package org.codehaus.groovy.grails.orm.hibernate.support; -import java.util.Properties; - -import javax.sql.DataSource; - -import org.apache.commons.lang.StringUtils; +import org.codehaus.groovy.grails.commons.GrailsApplication; import org.codehaus.groovy.grails.orm.hibernate.exceptions.CouldNotDetermineHibernateDialectException; +import org.codehaus.groovy.grails.plugins.support.aware.GrailsApplicationAware; import org.hibernate.HibernateException; import org.hibernate.dialect.Dialect; -import org.hibernate.dialect.DialectFactory; +import org.hibernate.dialect.resolver.DialectFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.MetaDataAccessException; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.util.Properties; /** * @author Steven Devijver */ -public class HibernateDialectDetectorFactoryBean implements FactoryBean, InitializingBean { +public class HibernateDialectDetectorFactoryBean implements FactoryBean, InitializingBean, GrailsApplicationAware { private DataSource dataSource; private Properties vendorNameDialectMappings; private String hibernateDialectClassName; private Dialect hibernateDialect; + private GrailsApplication grailsApplication; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; @@ -64,20 +68,33 @@ public void afterPropertiesSet() throws MetaDataAccessException { Assert.notNull(dataSource, "Data source is not set!"); Assert.notNull(vendorNameDialectMappings, "Vendor name/dialect mappings are not set!"); + Connection connection = null; + + String dbName = (String)JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName"); - Integer majorVersion = (Integer)JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseMajorVersion"); try { - hibernateDialect = DialectFactory.determineDialect(dbName,majorVersion.intValue()); - hibernateDialectClassName = hibernateDialect.getClass().getName(); - } - catch (HibernateException e) { - hibernateDialectClassName = vendorNameDialectMappings.getProperty(dbName); - } + connection = DataSourceUtils.getConnection(dataSource); + + try { + hibernateDialect = DialectFactory.buildDialect(grailsApplication.getConfig().toProperties(), connection); + hibernateDialectClassName = hibernateDialect.getClass().getName(); + } catch (HibernateException e) { + hibernateDialectClassName = vendorNameDialectMappings.getProperty(dbName); + } - if (StringUtils.isBlank(hibernateDialectClassName)) { - throw new CouldNotDetermineHibernateDialectException( - "Could not determine Hibernate dialect for database name [" + dbName + "]!"); + + if (!StringUtils.hasText(hibernateDialectClassName)) { + throw new CouldNotDetermineHibernateDialectException( + "Could not determine Hibernate dialect for database name [" + dbName + "]!"); + } + } finally { + DataSourceUtils.releaseConnection(connection,dataSource); } + + } + + public void setGrailsApplication(GrailsApplication grailsApplication) { + this.grailsApplication = grailsApplication; } } diff --git a/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDslTests.groovy b/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDslTests.groovy index c0f315a6f8a..843d9f77d47 100644 --- a/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDslTests.groovy +++ b/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDslTests.groovy @@ -1,7 +1,8 @@ package org.codehaus.groovy.grails.orm.hibernate -import javax.sql.DataSource import java.sql.Types +import javax.sql.DataSource +import org.hibernate.type.TextType /** * @author Graeme Rocher @@ -96,16 +97,18 @@ class MappingDslTests extends AbstractGrailsHibernateTests { def p = personClass.newInstance() p.firstName = "Wilma" - p.save(flush:true) p.addToChildren(firstName:"Dino", lastName:'Dinosaur') p.addToCousins(firstName:"Bob", lastName:'The Builder') p.save(flush:true) session.clear() - p = personClass.clazz.get(1) + personClass.clazz.withNewSession { + p = personClass.clazz.get(1) + + assertTrue p.children.wasInitialized() + assertFalse p.cousins.wasInitialized() + } - assertTrue p.children.wasInitialized() - assertFalse p.cousins.wasInitialized() } void testUserTypes() { @@ -117,20 +120,12 @@ class MappingDslTests extends AbstractGrailsHibernateTests { r.save() session.flush() - def con - try { - con = ds.getConnection() - def statement = con.prepareStatement("select * from relative") - def result = statement.executeQuery() - assertTrue result.next() - def metadata = result.getMetaData() - assertEquals "FIRST_NAME",metadata.getColumnLabel(3) - // h2 returns CLOB for text type, if it wasn't mapped as text it would be VARCHAR so this is an ok test - assertEquals( Types.CLOB, metadata.getColumnType(3) ) - } - finally { - con.close() - } + final cmd = session.getSessionFactory().getClassMetadata(relativeClass.clazz) + + final type = cmd.getPropertyType("firstName") + + assert type instanceof TextType + } void testCompositeIdMapping() { diff --git a/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PackagedCustomMappingTests.groovy b/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PackagedCustomMappingTests.groovy index e3026c45a84..2a8036b3557 100644 --- a/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PackagedCustomMappingTests.groovy +++ b/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PackagedCustomMappingTests.groovy @@ -28,10 +28,13 @@ class PackagedCustomMapping { session.clear() - test = testClass.get(1) - test.name = "Bob" - shouldFail(UnsupportedOperationException) { - test.save(flush:true) + testClass.withNewSession { + test = testClass.get(1) + test.name = "Bob" + shouldFail(IllegalStateException) { + test.save(flush:true) + } } + } } diff --git a/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SessionFactoryAdapter.java b/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SessionFactoryAdapter.java index ba2b65418a7..59b7f3d60a3 100644 --- a/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SessionFactoryAdapter.java +++ b/grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SessionFactoryAdapter.java @@ -7,9 +7,7 @@ import javax.naming.Reference; -import org.hibernate.Interceptor; -import org.hibernate.SessionFactory; -import org.hibernate.StatelessSession; +import org.hibernate.*; import org.hibernate.classic.Session; import org.hibernate.engine.FilterDefinition; import org.hibernate.metadata.ClassMetadata; @@ -99,6 +97,14 @@ public FilterDefinition getFilterDefinition(String arg0) { return null; } + public boolean containsFetchProfileDefinition(String name) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public TypeHelper getTypeHelper() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public Statistics getStatistics() { return null; } @@ -107,6 +113,10 @@ public boolean isClosed() { return false; } + public Cache getCache() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public Session openSession() { return null; }