Skip to content

Commit fdab4af

Browse files
committed
Merge branch '2.3.x' of github.com:grails/grails-core into 2.3.x
2 parents b215a12 + fc7d416 commit fdab4af

File tree

32 files changed

+651
-77
lines changed

32 files changed

+651
-77
lines changed

grails-bootstrap/src/main/groovy/org/codehaus/groovy/grails/cli/support/GrailsRootLoader.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,12 @@ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundE
5050
}
5151
return super.loadClass(name, resolve);
5252
}
53-
catch (LinkageError e) {
54-
return getParent().loadClass(name);
53+
catch (LinkageError primary) {
54+
try {
55+
return getParent().loadClass(name);
56+
} catch (ClassNotFoundException secondary) {
57+
throw primary;
58+
}
5559
}
5660
}
5761
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2012 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.codehaus.groovy.grails.cli.support
18+
19+
import org.apache.tools.ant.BuildLogger
20+
import org.apache.tools.ant.Project
21+
import spock.lang.Specification
22+
23+
/**
24+
25+
*/
26+
class GrailsRootLoaderSpec extends Specification {
27+
28+
def "NoClassDefFoundError is not obscured by ClassNotFoundException"() {
29+
// i.e., GrailsRootLoader does not throw ClassNotFoundException for a class that it actually did find.
30+
31+
setup: "tmp dir for the isolated classpath"
32+
File tmpDir = createTempDir("GrailsRootLoaderSpec", ".tmp")
33+
34+
and: "cut off class file A from its dependency B by copying only A to the tmp dir"
35+
copyClassFileToClasspath(A, tmpDir)
36+
37+
and: "parent ClassLoader has neither A nor B"
38+
def parent = createClassLoaderExcluding([A.name, B.name])
39+
40+
and: "GrailsRootLoader with just the tmp dir containing A"
41+
def grl = new GrailsRootLoader([tmpDir.toURI().toURL()] as URL[], parent)
42+
43+
when: "loading A"
44+
grl.loadClass(A.name)
45+
46+
then: "throws NoClassDefFoundError for B (not the parent's ClassNotFoundException for A)"
47+
NoClassDefFoundError e = thrown()
48+
e.message == B.name.replace('.', '/')
49+
50+
cleanup:
51+
tmpDir.deleteDir()
52+
}
53+
54+
static class A implements B {}
55+
56+
static interface B {}
57+
58+
private static File createTempDir(String prefix, String suffix) {
59+
File tmpDir = File.createTempFile(prefix, suffix)
60+
assert tmpDir.delete()
61+
assert tmpDir.mkdir()
62+
tmpDir
63+
}
64+
65+
private static void copyClassFileToClasspath(Class c, File baseDir) {
66+
String classFilePath = c.name.replace('.', '/').concat('.class')
67+
def source = new File(c.classLoader.getResource(classFilePath).path)
68+
def dest = new File(baseDir, classFilePath)
69+
70+
def quiet = new AntBuilder()
71+
quiet.antProject.buildListeners.find {it instanceof BuildLogger}?.messageOutputLevel = Project.MSG_WARN
72+
quiet.copy(file: source, tofile: dest) // also creates intervening package dirs
73+
}
74+
75+
76+
private static ClassLoader createClassLoaderExcluding(classNames) {
77+
new ClassLoader() {
78+
@Override
79+
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
80+
if (name in classNames) {
81+
throw new ClassNotFoundException(name)
82+
} else {
83+
super.loadClass(name, resolve)
84+
}
85+
}
86+
}
87+
}
88+
}

grails-core/src/main/groovy/org/codehaus/groovy/grails/commons/DomainClassArtefactHandler.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,17 @@ public boolean isArtefactClass(Class clazz) {
7474

7575
static final Map<Integer, Boolean> DOMAIN_CLASS_CHECK_CACHE = new ConcurrentHashMap<Integer, Boolean>();
7676

77+
public static boolean isDomainClass(Class<?> clazz, boolean allowProxyClass) {
78+
boolean retval = isDomainClass(clazz);
79+
if(!retval && allowProxyClass && clazz != null && clazz.getSimpleName().contains("$")) {
80+
retval = isDomainClass(clazz.getSuperclass());
81+
}
82+
return retval;
83+
}
84+
7785
public static boolean isDomainClass(Class<?> clazz) {
86+
if (clazz == null) return false;
87+
7888
Integer cacheKey = System.identityHashCode(clazz);
7989

8090
Boolean retval = DOMAIN_CLASS_CHECK_CACHE.get(cacheKey);
@@ -83,6 +93,7 @@ public static boolean isDomainClass(Class<?> clazz) {
8393
}
8494

8595
retval = doIsDomainClassCheck(clazz);
96+
8697
if (!developmentMode) {
8798
DOMAIN_CLASS_CHECK_CACHE.put(cacheKey, retval);
8899
}
@@ -91,8 +102,6 @@ public static boolean isDomainClass(Class<?> clazz) {
91102

92103
private static boolean doIsDomainClassCheck(Class<?> clazz) {
93104
// it's not a closure
94-
if (clazz == null) return false;
95-
96105
if (Closure.class.isAssignableFrom(clazz)) {
97106
return false;
98107
}

grails-core/src/main/groovy/org/codehaus/groovy/grails/support/encoding/CodecMetaClassSupport.groovy

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import groovy.transform.CompileStatic
2020

2121
import org.codehaus.groovy.grails.commons.GrailsCodecClass
2222
import org.codehaus.groovy.runtime.GStringImpl
23+
import org.codehaus.groovy.runtime.NullObject
2324

2425
/**
2526
* Helper methods for Codec metaclass operations.
@@ -53,7 +54,7 @@ class CodecMetaClassSupport {
5354
->
5455
def encoder = codecClass.getEncoder()
5556
if (encoder) {
56-
return encoder.encode(delegate)
57+
return encoder.encode(delegate != NullObject.NullObject ? delegate : null)
5758
}
5859

5960
// note the call to delegate.getClass() instead of the more groovy delegate.class.
@@ -66,7 +67,7 @@ class CodecMetaClassSupport {
6667
->
6768
def decoder = codecClass.getDecoder()
6869
if (decoder) {
69-
return decoder.decode(delegate)
70+
return decoder.decode(delegate != NullObject.NullObject ? delegate : null)
7071
}
7172

7273
// note the call to delegate.getClass() instead of the more groovy delegate.class.
@@ -79,13 +80,13 @@ class CodecMetaClassSupport {
7980
// Resolve codec methods once only at startup
8081
def encoder = codecClass.getEncoder()
8182
if (encoder) {
82-
encoderClosure = { -> encoder.encode(delegate) }
83+
encoderClosure = { -> encoder.encode(delegate != NullObject.NullObject ? delegate : null) }
8384
} else {
8485
encoderClosure = { -> throw new MissingMethodException(encodeMethodName, delegate.getClass(), EMPTY_ARGS) }
8586
}
8687
def decoder = codecClass.getDecoder()
8788
if (decoder) {
88-
decoderClosure = { -> decoder.decode(delegate) }
89+
decoderClosure = { -> decoder.decode(delegate != NullObject.NullObject ? delegate : null) }
8990
} else {
9091
decoderClosure = { -> throw new MissingMethodException(decodeMethodName, delegate.getClass(), EMPTY_ARGS) }
9192
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ class SimpleDataBinder implements DataBinder {
318318
indexedInstance = genericType.newInstance()
319319
bind indexedInstance, val, listener
320320
addElementToCollectionAt obj, propName, collectionInstance, index, indexedInstance
321+
} else if(genericType.isEnum() && val instanceof CharSequence) {
322+
def enumValue = convertStringToEnum(genericType, val.toString())
323+
addElementToCollectionAt obj, propName, collectionInstance, index, enumValue
321324
}
322325
} else {
323326
addElementToCollectionAt obj, propName, collectionInstance, index, val
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.grails.databinding
2+
3+
import spock.lang.Issue
4+
import spock.lang.Specification
5+
6+
class SimpleDataBinderEnumBindingSpec extends Specification {
7+
@Issue('GRAILS-10979')
8+
void 'Test binding to a List of enum'() {
9+
given:
10+
def binder = new SimpleDataBinder()
11+
def holder = new HatSizeHolder()
12+
13+
when:
14+
binder.bind holder, ['sizes[0]': 'LARGE', 'sizes[1]': 'SMALL'] as SimpleMapDataBindingSource
15+
16+
then:
17+
holder.sizes?.size() == 2
18+
holder.sizes[0] == HatSize.LARGE
19+
holder.sizes[1] == HatSize.SMALL
20+
}
21+
22+
}
23+
24+
enum HatSize {
25+
SMALL, MEDIUM, LARGE
26+
}
27+
28+
class HatSizeHolder {
29+
List<HatSize> sizes
30+
}

grails-plugin-codecs/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
dependencies {
22
compile 'commons-codec:commons-codec:1.6'
3-
compile project(":grails-web")
4-
}
3+
compile project(":grails-web"), project(":grails-plugin-converters")
4+
}

grails-plugin-codecs/src/main/groovy/org/codehaus/groovy/grails/plugins/CodecsGrailsPlugin.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import org.codehaus.groovy.grails.plugins.codecs.SHA256BytesCodec
3333
import org.codehaus.groovy.grails.plugins.codecs.SHA256Codec
3434
import org.codehaus.groovy.grails.plugins.codecs.URLCodec
3535
import org.codehaus.groovy.grails.plugins.codecs.XMLCodec
36+
import org.codehaus.groovy.grails.plugins.codecs.JSONCodec
3637

3738
/**
3839
* Configures pluggable codecs.
@@ -48,6 +49,7 @@ class CodecsGrailsPlugin {
4849
HTMLCodec,
4950
HTML4Codec,
5051
XMLCodec,
52+
JSONCodec,
5153
JavaScriptCodec,
5254
URLCodec,
5355
Base64Codec,

grails-plugin-codecs/src/main/groovy/org/codehaus/groovy/grails/plugins/codecs/AbstractCharReplacementEncoder.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ public AbstractCharReplacementEncoder(CodecIdentifier codecIdentifier) {
5454
* @see org.codehaus.groovy.grails.support.encoding.Encoder#encode(java.lang.Object)
5555
*/
5656
public Object encode(Object o) {
57+
return doCharReplacementEncoding(o);
58+
}
59+
60+
protected final Object doCharReplacementEncoding(Object o) {
5761
if (o == null) {
5862
return null;
5963
}
@@ -72,9 +76,17 @@ else if (o instanceof Character) {
7276
}
7377
}
7478
else {
75-
str = String.valueOf(o);
79+
str = convertToString(o);
7680
}
7781

82+
return escapeCharSequence(str);
83+
}
84+
85+
protected String convertToString(Object o) {
86+
return String.valueOf(o);
87+
}
88+
89+
protected Object escapeCharSequence(CharSequence str) {
7890
if (str == null || str.length() == 0) {
7991
return str;
8092
}

grails-plugin-codecs/src/main/groovy/org/codehaus/groovy/grails/plugins/codecs/HTMLEncoder.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,8 @@ public class HTMLEncoder extends XMLEncoder {
3232
public HTMLEncoder() {
3333
super(HTML_CODEC_IDENTIFIER);
3434
}
35+
36+
protected Object doEncode(Object o) {
37+
return doCharReplacementEncoding(o);
38+
}
3539
}

0 commit comments

Comments
 (0)