Skip to content

Commit 12476ec

Browse files
committed
Merge branch '2.3.x' of github.com:grails/grails-core into 2.3.x
2 parents 41b3cc6 + 2252523 commit 12476ec

File tree

10 files changed

+171
-15
lines changed

10 files changed

+171
-15
lines changed

gradle/assemble.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ task pluginsFromRepo {
104104
jquery: "1.11.0.2",
105105
resources: "1.2.7",
106106
scaffolding: "2.0.2",
107-
tomcat: "7.0.52",
107+
tomcat: "7.0.52.1",
108108
webxml: "1.4.1"
109109
]
110110

grails-databinding/src/main/groovy/org/grails/databinding/SimpleDataBinder.groovy

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,11 @@ class SimpleDataBinder implements DataBinder {
467467
if (formattedConverter) {
468468
converter = { SimpleMapDataBindingSource source ->
469469
def value = source.getPropertyValue field.name
470-
formattedConverter.convert (value, formattingValue)
470+
def convertedValue = null
471+
if(value != null) {
472+
convertedValue = formattedConverter.convert (value, formattingValue)
473+
}
474+
convertedValue
471475
} as ValueConverter
472476
}
473477
converter

grails-resources/src/grails/grails-app/conf/BuildConfig.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ grails.project.dependency.resolution = {
5454

5555
plugins {
5656
// plugins for the build system only
57-
build ":tomcat:7.0.52"
57+
build ":tomcat:7.0.52.1"
5858

5959
// plugins for the compile step
6060
compile ":scaffolding:2.0.2"

grails-resources/src/grails/grails-app/conf/Config.groovy

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ grails.exceptionresolver.params.exclude = ['password']
8383
// configure auto-caching of queries by default (if false you can cache individual queries with 'cache: true')
8484
grails.hibernate.cache.queries = false
8585

86+
// configure passing transaction's read-only attribute to Hibernate session, queries and criterias
87+
// set "singleSession = false" OSIV mode in hibernate configuration after enabling
88+
grails.hibernate.pass.readonly = false
89+
// configure passing read-only to OSIV session by default, requires "singleSession = false" OSIV mode
90+
grails.hibernate.osiv.readonly = false
91+
8692
environments {
8793
development {
8894
grails.logging.jul.usebridge = true

grails-resources/src/grails/grails-app/conf/DataSource.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ hibernate {
1010
cache.use_query_cache = false
1111
cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory' // Hibernate 3
1212
// cache.region.factory_class = 'org.hibernate.cache.ehcache.EhCacheRegionFactory' // Hibernate 4
13+
singleSession = true // configure OSIV singleSession mode
1314
}
1415

1516
// environment specific settings

grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/GrailsWebDataBinderBindingXmlSpec.groovy

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import grails.persistence.Entity
44
import grails.test.mixin.Mock
55
import grails.test.mixin.TestMixin
66
import grails.test.mixin.domain.DomainClassUnitTestMixin
7+
import grails.validation.Validateable
78

89
import org.codehaus.groovy.grails.web.binding.GrailsWebDataBinder
910

@@ -71,6 +72,61 @@ class GrailsWebDataBinderBindingXmlSpec extends Specification {
7172
writer.books[1].publisher == 'Publisher Two'
7273
writer.books[1].title == 'Book Two'
7374
}
75+
76+
@Issue('GRAILS-11175')
77+
void 'Test binding a single XML child element to a List in a non domain class'() {
78+
given:
79+
def binder = new GrailsWebDataBinder(grailsApplication)
80+
def obj = new CommandObject()
81+
82+
when:
83+
def xml = new XmlSlurper().parseText("""
84+
<commandObject>
85+
<somethings>
86+
<something><name>One</name></something>
87+
</somethings>
88+
</commandObject>
89+
""")
90+
binder.bind obj, xml
91+
92+
then:
93+
!obj.hasErrors()
94+
obj.somethings?.size() == 1
95+
obj.somethings[0].name == 'One'
96+
}
97+
98+
@Issue('GRAILS-11175')
99+
void 'Test binding multiple XML child elements to a List in a non domain class'() {
100+
given:
101+
def binder = new GrailsWebDataBinder(grailsApplication)
102+
def obj = new CommandObject()
103+
104+
when:
105+
def xml = new XmlSlurper().parseText("""
106+
<commandObject>
107+
<somethings>
108+
<something><name>One</name></something>
109+
<something><name>Two</name></something>
110+
</somethings>
111+
</commandObject>
112+
""")
113+
binder.bind obj, xml
114+
115+
then:
116+
!obj.hasErrors()
117+
obj.somethings?.size() == 2
118+
obj.somethings[0].name == 'One'
119+
obj.somethings[1].name == 'Two'
120+
}
121+
}
122+
123+
@Validateable
124+
class CommandObject {
125+
List<Something> somethings
126+
}
127+
128+
class Something {
129+
String name
74130
}
75131

76132
@Entity

grails-test-suite-persistence/src/test/groovy/org/codehaus/groovy/grails/orm/GrailsWebDataBinderSpec.groovy

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,24 @@ import org.grails.databinding.events.DataBindingListenerAdapter
3333

3434
import spock.lang.Issue
3535
import spock.lang.Specification
36+
import spock.lang.Unroll
3637

3738
import com.google.gson.internal.LazilyParsedNumber
3839

3940
@TestMixin(DomainClassUnitTestMixin)
4041
@Mock([Foo, AssociationBindingAuthor, AssociationBindingPage, AssociationBindingBook, Author, Child, CollectionContainer, DataBindingBook, Fidget, Parent, Publication, Publisher, Team, Widget])
4142
class GrailsWebDataBinderSpec extends Specification {
43+
private static Locale defaultLocale = Locale.getDefault()
4244

4345
GrailsWebDataBinder binder
4446

4547
void setup() {
4648
binder = grailsApplication.mainContext.getBean(DataBindingUtils.DATA_BINDER_BEAN_NAME)
4749
}
50+
51+
void cleanup() {
52+
Locale.setDefault(defaultLocale)
53+
}
4854

4955
void 'Test binding an invalid String to an object reference does not result in an empty instance being bound'() {
5056
// GRAILS-3159
@@ -92,8 +98,10 @@ class GrailsWebDataBinderSpec extends Specification {
9298
obj.stringWithSpecialBinding == ''
9399
}
94100

95-
void 'Test binding to primitives from Strings'() {
101+
@Unroll
102+
void 'Test binding to primitives from Strings when locale is #locale'() {
96103
given:
104+
Locale.setDefault(locale)
97105
def obj = new PrimitiveContainer()
98106

99107
when:
@@ -103,8 +111,8 @@ class GrailsWebDataBinderSpec extends Specification {
103111
someShort: '2',
104112
someInt: '3',
105113
someLong: '4',
106-
someFloat: '5.5',
107-
someDouble: '6.6']))
114+
someFloat: '5.5'.replace('.', decimalSeparator),
115+
someDouble: '6.6'.replace('.', decimalSeparator)]))
108116

109117
then:
110118
obj.someBoolean == true
@@ -115,6 +123,9 @@ class GrailsWebDataBinderSpec extends Specification {
115123
obj.someLong == 4
116124
obj.someFloat == 5.5
117125
obj.someDouble == 6.6
126+
where:
127+
locale << [Locale.getInstance("fi", "FI", ""), Locale.getInstance("en", "US", "")]
128+
decimalSeparator << [',', '.']
118129
}
119130

120131
void 'Test binding null to id of element nested in a List'() {
@@ -1207,6 +1218,27 @@ class GrailsWebDataBinderSpec extends Specification {
12071218
obj.objectIds[3] instanceof ObjectId
12081219
obj.objectIds[3].value == 'eight'
12091220
}
1221+
1222+
@Issue('GRAILS-11174')
1223+
void 'Test binding null to a Date marked with @BindingFormat'() {
1224+
given:
1225+
def obj = new DataBindingBook()
1226+
1227+
when:
1228+
binder.bind obj, [datePublished: null] as SimpleMapDataBindingSource
1229+
1230+
then:
1231+
obj.datePublished == null
1232+
!obj.hasErrors()
1233+
1234+
when:
1235+
obj.datePublished = new Date()
1236+
binder.bind obj, [datePublished: null] as SimpleMapDataBindingSource
1237+
1238+
then:
1239+
obj.datePublished == null
1240+
!obj.hasErrors()
1241+
}
12101242
}
12111243

12121244
@Entity
@@ -1317,6 +1349,8 @@ class DataBindingBook {
13171349
String title
13181350
List importantPageNumbers
13191351
List topics
1352+
@BindingFormat("MMddyyyy")
1353+
Date datePublished
13201354
static hasMany = [topics: String, importantPageNumbers: Integer]
13211355
}
13221356

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.codehaus.groovy.grails.web.binding
2+
3+
import grails.persistence.Entity
4+
import spock.lang.Issue
5+
import spock.lang.Specification
6+
7+
8+
class DefaultASTDatabindingHelperDomainClassSpecialPropertiesSpec extends
9+
Specification {
10+
11+
@Issue('GRAILS-11173')
12+
void 'Test binding to special properties in a domain class'() {
13+
when:
14+
def now = new Date()
15+
def obj = new SomeDomainClass(dateCreated: now, lastUpdated: now)
16+
17+
then:
18+
obj.dateCreated == null
19+
obj.lastUpdated == null
20+
}
21+
22+
@Issue('GRAILS-11173')
23+
void 'Test binding to special properties in a domain class with explicit bindable rules'() {
24+
when:
25+
def now = new Date()
26+
def obj = new SomeDomainClassWithExplicitBindableRules(dateCreated: now, lastUpdated: now)
27+
28+
then:
29+
obj.dateCreated == now
30+
obj.lastUpdated == now
31+
}
32+
}
33+
34+
@Entity
35+
class SomeDomainClass {
36+
Date dateCreated
37+
Date lastUpdated
38+
}
39+
40+
@Entity
41+
class SomeDomainClassWithExplicitBindableRules {
42+
Date dateCreated
43+
Date lastUpdated
44+
45+
static constraints = {
46+
dateCreated bindable: true
47+
lastUpdated bindable: true
48+
}
49+
}

grails-web/src/main/groovy/org/codehaus/groovy/grails/web/binding/DefaultASTDatabindingHelper.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.codehaus.groovy.grails.web.binding;
1717

18+
import grails.util.CollectionUtils;
1819
import grails.util.GrailsNameUtils;
1920

2021
import java.lang.reflect.Modifier;
@@ -30,6 +31,7 @@
3031
import java.util.Set;
3132

3233
import grails.web.controllers.ControllerMethod;
34+
3335
import org.codehaus.groovy.ast.*;
3436
import org.codehaus.groovy.ast.expr.ClosureExpression;
3537
import org.codehaus.groovy.ast.expr.ConstantExpression;
@@ -72,6 +74,8 @@ public class DefaultASTDatabindingHelper implements ASTDatabindingHelper {
7274
add(new ClassNode(String.class));
7375
add(new ClassNode(URL.class));
7476
}};
77+
78+
private static final Set<String> DOMAIN_CLASS_PROPERTIES_TO_EXCLUDE_BY_DEFAULT = CollectionUtils.newSet("id", "version", "dateCreated", "lastUpdated");
7579

7680
public void injectDatabindingCode(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) {
7781
addDefaultDatabindingWhitelistField(source, classNode);
@@ -249,7 +253,7 @@ private boolean shouldFieldBeInWhiteList(final FieldNode fieldNode, final Set<St
249253
fieldNode.getType().equals(new ClassNode(Object.class))) {
250254
shouldInclude = false;
251255
} else if (isDomainClass) {
252-
if ("id".equals(fieldName) || "version".equals(fieldName)) {
256+
if (DOMAIN_CLASS_PROPERTIES_TO_EXCLUDE_BY_DEFAULT.contains(fieldName)) {
253257
shouldInclude = false;
254258
}
255259
}

grails-web/src/main/groovy/org/codehaus/groovy/grails/web/binding/GrailsWebDataBinder.groovy

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ class GrailsWebDataBinder extends SimpleDataBinder {
279279
}
280280
} else if(Collection.isAssignableFrom(metaProperty.type)) {
281281
def referencedType = getReferencedTypeForCollection(propName, obj)
282-
if(referencedType && isDomainClass(referencedType)) {
282+
if(referencedType) {
283283
def listValue
284284
if(val instanceof List) {
285285
listValue = (List)val
@@ -301,13 +301,15 @@ class GrailsWebDataBinder extends SimpleDataBinder {
301301
def itemsWhichNeedBinding = []
302302
listValue.each { item ->
303303
def persistentInstance
304-
if(item instanceof Map || item instanceof DataBindingSource) {
305-
def idValue = getIdentifierValueFrom(item)
306-
if(idValue != null) {
307-
persistentInstance = getPersistentInstance(referencedType, idValue)
308-
if(persistentInstance != null) {
309-
bind persistentInstance, new SimpleMapDataBindingSource(item), listener
310-
itemsWhichNeedBinding << persistentInstance
304+
if(isDomainClass(referencedType)) {
305+
if(item instanceof Map || item instanceof DataBindingSource) {
306+
def idValue = getIdentifierValueFrom(item)
307+
if(idValue != null) {
308+
persistentInstance = getPersistentInstance(referencedType, idValue)
309+
if(persistentInstance != null) {
310+
bind persistentInstance, new SimpleMapDataBindingSource(item), listener
311+
itemsWhichNeedBinding << persistentInstance
312+
}
311313
}
312314
}
313315
}

0 commit comments

Comments
 (0)