Skip to content

Commit c2a1e8b

Browse files
author
graeme
committed
fix for GRAILS-1686
git-svn-id: https://svn.codehaus.org/grails/trunk@5751 1cfb16fd-6d17-0410-8ff1-b7e8e1e2867d
1 parent 727a468 commit c2a1e8b

File tree

6 files changed

+101
-11
lines changed

6 files changed

+101
-11
lines changed

src/commons/org/codehaus/groovy/grails/commons/DefaultGrailsDomainClass.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ private void establishDomainClassRelationship(DefaultGrailsDomainClassProperty p
504504

505505
// if there is only one property on many-to-one side of the relationship then
506506
// try to establish if it is bidirectional
507-
if(descriptors.length == 1) {
507+
if(descriptors.length == 1 && isNotMappedToDifferentProperty(property,relatedClassPropertyName, mappedBy)) {
508508
if(!StringUtils.isBlank(relatedClassPropertyName)) {
509509
property.setReferencePropertyName(relatedClassPropertyName);
510510
// get the type of the property
@@ -545,8 +545,15 @@ else if(descriptors.length > 1) {
545545
// establish relationship based on this type
546546
establishDomainClassRelationshipToType( property, relatedClassPropertyType );
547547
}
548+
549+
private boolean isNotMappedToDifferentProperty(GrailsDomainClassProperty property, String relatedClassPropertyName, Map mappedBy) {
550+
String mappedByForRelation = (String)mappedBy.get(relatedClassPropertyName);
551+
if(mappedByForRelation == null) return true;
552+
else if(!property.getName().equals(mappedByForRelation)) return false;
553+
return true;
554+
}
548555

549-
private String findOneToManyThatMatchesType(DefaultGrailsDomainClassProperty property, Map relatedClassRelationships) {
556+
private String findOneToManyThatMatchesType(DefaultGrailsDomainClassProperty property, Map relatedClassRelationships) {
550557
String relatedClassPropertyName = null;
551558
for(Iterator i = relatedClassRelationships.keySet().iterator();i.hasNext();) {
552559
String currentKey = (String)i.next();
@@ -720,4 +727,8 @@ public Set getSubClasses() {
720727
public void refreshConstraints() {
721728
evaluateConstraints();
722729
}
730+
731+
public Map getMappedBy() {
732+
return mappedBy;
733+
}
723734
}

src/commons/org/codehaus/groovy/grails/commons/GrailsClassUtils.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@
1717

1818
import groovy.lang.*;
1919
import org.apache.commons.lang.StringUtils;
20-
import org.springframework.beans.BeanUtils;
21-
import org.springframework.beans.BeanWrapper;
22-
import org.springframework.beans.BeanWrapperImpl;
23-
import org.springframework.beans.BeansException;
20+
import org.springframework.beans.*;
2421
import org.springframework.util.Assert;
2522

2623
import java.beans.PropertyDescriptor;
@@ -100,8 +97,14 @@ public static Object getPropertyValueOfNewInstance(Class clazz, String propertyN
10097
if(clazz == null || StringUtils.isBlank(propertyName))
10198
return null;
10299

103-
Object instance = BeanUtils.instantiateClass(clazz);
104-
100+
Object instance = null;
101+
try {
102+
instance = BeanUtils.instantiateClass(clazz);
103+
} catch (BeanInstantiationException e) {
104+
return null;
105+
}
106+
107+
105108
return getPropertyOrStaticPropertyOrFieldValue(instance, propertyName);
106109
}
107110

src/commons/org/codehaus/groovy/grails/commons/GrailsDomainClass.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,4 +178,9 @@ public interface GrailsDomainClass extends GrailsClass {
178178
* @return True if it does
179179
*/
180180
boolean hasSubClasses();
181+
182+
/**
183+
* @return The map that defines association mappings
184+
*/
185+
Map getMappedBy();
181186
}

src/commons/org/codehaus/groovy/grails/commons/GrailsDomainConfigurationUtil.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,11 @@ public static void configureDomainClassRelationships(GrailsClass[] domainClasses
9999
for (int k = 0; k < referencedProperties.length; k++) {
100100
// for bi-directional circular dependencies we don't want the other side
101101
// to be equal to self
102-
if(prop.equals(referencedProperties[k]) && prop.isBidirectional())
102+
GrailsDomainClassProperty referencedProp = referencedProperties[k];
103+
if(prop.equals(referencedProp) && prop.isBidirectional())
103104
continue;
104-
if(domainClasses[i].getClazz().equals(referencedProperties[k].getReferencedPropertyType())) {
105-
prop.setOtherSide(referencedProperties[k]);
105+
if(isCandidateForOtherSide(domainClass, prop, referencedProp)) {
106+
prop.setOtherSide(referencedProp);
106107
break;
107108
}
108109
}
@@ -114,6 +115,15 @@ public static void configureDomainClassRelationships(GrailsClass[] domainClasses
114115
}
115116
}
116117

118+
private static boolean isCandidateForOtherSide(GrailsDomainClass domainClass, GrailsDomainClassProperty prop, GrailsDomainClassProperty referencedProp) {
119+
boolean isTypeCompatible = domainClass.getClazz().equals(referencedProp.getReferencedPropertyType());
120+
Map mappedBy = domainClass.getMappedBy();
121+
122+
Object propertyMapping = mappedBy.get(prop.getName());
123+
return !(propertyMapping != null && !propertyMapping.equals(referencedProp.getName())) && isTypeCompatible;
124+
125+
}
126+
117127
/**
118128
* Returns the ORM frameworks mapping file name for the specified class name
119129
*

src/persistence/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClass.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ public boolean hasSubClasses() {
214214
return false;
215215
}
216216

217+
public Map getMappedBy() {
218+
return Collections.EMPTY_MAP;
219+
}
220+
217221
public boolean isOneToMany(String propertyName) {
218222
GrailsDomainClassProperty prop = getPropertyByName(propertyName);
219223
return prop != null && prop.isOneToMany();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Tests a many-to-many and one-to-one relationship used together
3+
4+
* @author Graeme Rocher
5+
* @since 1.0
6+
*
7+
* Created: Oct 12, 2007
8+
*/
9+
package org.codehaus.groovy.grails.orm.hibernate
10+
11+
import org.codehaus.groovy.grails.commons.GrailsDomainClass
12+
13+
class ManyToManyAndOneToOneTests extends AbstractGrailsHibernateTests {
14+
15+
protected void onSetUp() {
16+
gcl.parseClass('''
17+
class Book {
18+
Long version
19+
Long id
20+
static belongsTo = Author
21+
Set authors
22+
23+
static hasMany = [authors:Author]
24+
static mappedBy = [authors:"books"]
25+
String title
26+
}
27+
class Author {
28+
Long version
29+
Long id
30+
31+
Set books
32+
static hasMany = [books:Book]
33+
static mappedBy = [books:"authors"]
34+
String name
35+
Book bookOther
36+
}
37+
''')
38+
}
39+
40+
void testDomain() {
41+
GrailsDomainClass bookClass = ga.getDomainClass("Book")
42+
GrailsDomainClass authorClass = ga.getDomainClass("Author")
43+
assert authorClass
44+
assertTrue authorClass.getPropertyByName("bookOther").isOneToOne()
45+
assertTrue authorClass.getPropertyByName("books").isManyToMany()
46+
assertEquals "authors",authorClass.getPropertyByName("books").otherSide.name
47+
assertFalse authorClass.getPropertyByName("bookOther").isBidirectional()
48+
49+
assert bookClass
50+
assert bookClass.getPropertyByName("authors").isManyToMany()
51+
assertEquals "books",bookClass.getPropertyByName("authors").otherSide.name
52+
53+
54+
55+
}
56+
57+
}

0 commit comments

Comments
 (0)