Skip to content

Commit 33f209a

Browse files
committed
Merge branch '3.1.x' of github.com:grails/grails-core into 3.1.x
2 parents 2f49412 + 59ddbae commit 33f209a

File tree

7 files changed

+77
-5
lines changed

7 files changed

+77
-5
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
classes
12
*.swp
23
/src
34
/out

grails-core/src/main/groovy/grails/plugins/DefaultGrailsPluginManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ private void loadDelayedPlugins() {
478478
}
479479
else {
480480
failedPlugins.put(plugin.getName(), plugin);
481-
LOG.warn("WARNING: Plugin [" + plugin.getName() + "] cannot be loaded because its dependencies [" +
481+
LOG.error("ERROR: Plugin [" + plugin.getName() + "] cannot be loaded because its dependencies [" +
482482
DefaultGroovyMethods.inspect(plugin.getDependencyNames()) + "] cannot be resolved");
483483
}
484484
}

grails-core/src/main/groovy/grails/util/GrailsClassUtils.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,11 +1028,50 @@ public static boolean isGetter(String name, Class<?>[] args) {
10281028

10291029
if (name.startsWith("get")) {
10301030
name = name.substring(3);
1031-
if (name.length() > 0 && Character.isUpperCase(name.charAt(0))) return true;
1031+
if (isPropertyMethodSuffix(name)) return true;
10321032
}
10331033
else if (name.startsWith("is")) {
10341034
name = name.substring(2);
1035-
if (name.length() > 0 && Character.isUpperCase(name.charAt(0))) return true;
1035+
if (isPropertyMethodSuffix(name)) return true;
1036+
}
1037+
return false;
1038+
}
1039+
1040+
/**
1041+
* This method is used when interrogating a method name to determine if the
1042+
* method represents a property getter. For example, if a method is named
1043+
* <code>getSomeProperty</code>, the value <code>"SomeProperty"</code> could
1044+
* be passed to this method to determine that the method should be considered
1045+
* a property getter. Examples of suffixes that would be considered property
1046+
* getters:
1047+
* <ul>
1048+
* <li>SomeProperty</li>
1049+
* <li>Word</li>
1050+
* <li>aProperty</li>
1051+
* <li>S</li>
1052+
* </ul>
1053+
*
1054+
* Example sof suffixes that would not be considered property getters:
1055+
* <ul>
1056+
* <li>someProperty</li>
1057+
* <li>word</li>
1058+
* <li>s</li>
1059+
* </ul>
1060+
* @param suffix The suffix to inspect
1061+
* @return true if suffix indicates a property name
1062+
*/
1063+
protected static boolean isPropertyMethodSuffix(String suffix) {
1064+
if (suffix.length() > 0) {
1065+
if(suffix.length() == 1) {
1066+
if(Character.isUpperCase(suffix.charAt(0))) {
1067+
return true;
1068+
}
1069+
} else {
1070+
if(Character.isUpperCase(suffix.charAt(0)) ||
1071+
(Character.isUpperCase(suffix.charAt(1)) && Character.isLowerCase(suffix.charAt(0)))) {
1072+
return true;
1073+
}
1074+
}
10361075
}
10371076
return false;
10381077
}

grails-shell/src/main/groovy/org/grails/cli/profile/commands/factory/ApplicationContextCommandFactory.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.grails.cli.profile.commands.factory
1717

18+
import grails.build.logging.GrailsConsole
1819
import grails.util.Named
1920
import org.grails.cli.gradle.commands.GradleTaskCommandAdapter
2021
import org.grails.cli.profile.Command
@@ -40,6 +41,7 @@ class ApplicationContextCommandFactory implements CommandFactory {
4041

4142
return commands.collect() { Named named -> new GradleTaskCommandAdapter(profile, named) }
4243
} catch (Throwable e) {
44+
GrailsConsole.instance.error("Error occurred loading commands: $e.message", e)
4345
return []
4446
}
4547
}

grails-test-suite-uber/src/test/groovy/grails/validation/DomainClassValidationSpec.groovy

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class DomainClassValidationSpec extends Specification {
3939

4040
void 'Test validate can be invoked in a unit test with no special configuration'() {
4141
when: 'an object is valid'
42-
def domainClass = new MyDomainClass(name: 'Kirk', age: 47, town: 'STL')
42+
def domainClass = new MyDomainClass(name: 'Kirk', age: 47, town: 'STL', aString: 'Woot!')
4343

4444
then: 'validate() returns true and there are no errors'
4545
domainClass.validate()
@@ -85,6 +85,7 @@ class DomainClassValidationSpec extends Specification {
8585
domainClass.errors.getFieldError('age').rejectedValue == 'type mismatched'
8686

8787
when:
88+
domainClass.aString = 'Woot!'
8889
domainClass.name = 'lower case'
8990
domainClass.age = -1 // invalid value
9091
domainClass.town = ''
@@ -111,6 +112,7 @@ class DomainClassValidationSpec extends Specification {
111112
domainClass.errors.getFieldError('age').rejectedValue == 'any validation failure'
112113

113114
when:
115+
domainClass.aString = 'Woot!'
114116
domainClass.name = 'lower case'
115117
domainClass.age = -1 // invalid value
116118
domainClass.town = ''
@@ -137,17 +139,19 @@ class DomainClassValidationSpec extends Specification {
137139
def constraints = getAssociatedDomainClassFromApplication(new MyDomainClass()).getConstrainedProperties()
138140

139141
then:
140-
constraints.size() == 4
142+
constraints.size() == 5
141143
constraints.containsKey 'name'
142144
constraints.containsKey 'town'
143145
constraints.containsKey 'age'
144146
constraints.containsKey 'someProperty'
147+
constraints.containsKey 'aString'
145148

146149
and:
147150
constraints.name.appliedConstraints.size() == 2
148151
constraints.age.appliedConstraints.size() == 2
149152
constraints.town.appliedConstraints.size() == 1
150153
constraints.someProperty.appliedConstraints.size() == 1
154+
constraints.aString.appliedConstraints.size() == 1
151155

152156
and:
153157
constraints.name.hasAppliedConstraint 'matches'
@@ -156,12 +160,14 @@ class DomainClassValidationSpec extends Specification {
156160
constraints.age.hasAppliedConstraint 'nullable'
157161
constraints.town.hasAppliedConstraint 'nullable'
158162
constraints.someProperty.hasAppliedConstraint 'nullable'
163+
constraints.aString.hasAppliedConstraint 'nullable'
159164

160165
and: 'implicit defaultNullable is nullable:false'
161166
!constraints.name.nullable
162167
!constraints.age.nullable
163168
!constraints.town.nullable
164169
!constraints.someProperty.nullable
170+
!constraints.aString.nullable
165171
}
166172

167173
@Ignore('defaultNullable is not supported yet')
@@ -307,6 +313,7 @@ class MyDomainClass {
307313
String name
308314
Integer age
309315
String town
316+
String aString
310317
private String _someProperty = 'default value'
311318

312319
void setSomeOtherProperty(String s) {}

grails-test-suite-uber/src/test/groovy/org/grails/commons/GrailsClassUtilsTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import grails.util.GrailsClassUtils;
1818
import junit.framework.TestCase;
19+
import spock.lang.Issue;
1920

2021
import javax.servlet.http.HttpServletRequest;
2122
import java.util.Date;
@@ -311,6 +312,14 @@ public void testIsPropertyGetter() throws Exception {
311312
assertFalse(GrailsClassUtils.isPropertyGetter(ClassHavingPropertyGetters.class.getDeclaredMethod("getFilename", String.class)));
312313
assertFalse(GrailsClassUtils.isPropertyGetter(ClassHavingPropertyGetters.class.getDeclaredMethod("getTitle", null)));
313314
}
315+
316+
@Issue("https://github.com/grails/grails-core/issues/10343")
317+
public void testPropertiesBeginningWithSingleLowerCaseLetter() throws Exception {
318+
assertTrue(GrailsClassUtils.isPropertyGetter(SomeGroovyClass.class.getDeclaredMethod("getaString", null)));
319+
assertTrue(GrailsClassUtils.isPropertyGetter(SomeGroovyClass.class.getDeclaredMethod("isaBoolean", null)));
320+
assertTrue(GrailsClassUtils.isPropertyGetter(SomeGroovyClass.class.getDeclaredMethod("getS", null)));
321+
assertTrue(GrailsClassUtils.isPropertyGetter(SomeGroovyClass.class.getDeclaredMethod("isB", null)));
322+
}
314323
}
315324

316325
class ClassWithStaticFieldAndStaticPropertyWithSameName {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.grails.commons
2+
3+
class SomeGroovyClass {
4+
String s
5+
String aString
6+
7+
boolean isaBoolean() {
8+
true
9+
}
10+
11+
boolean isB() {
12+
true
13+
}
14+
}

0 commit comments

Comments
 (0)