Skip to content

Commit 2d21b8d

Browse files
committed
Fix tests to allow getterOnly constrained. Fix GrailsClassUtils.isGetter to check for boolean
1 parent 04bb858 commit 2d21b8d

File tree

6 files changed

+57
-35
lines changed

6 files changed

+57
-35
lines changed

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ public static boolean isPropertyInherited(Class clz, String propertyName) {
940940
* @return true if the method is a property getter
941941
*/
942942
public static boolean isPropertyGetter(Method method) {
943-
return !Modifier.isStatic(method.getModifiers()) && Modifier.isPublic(method.getModifiers()) && isGetter(method.getName(), method.getParameterTypes());
943+
return !Modifier.isStatic(method.getModifiers()) && Modifier.isPublic(method.getModifiers()) && isGetter(method.getName(), method.getReturnType(), method.getParameterTypes());
944944
}
945945

946946
/**
@@ -1022,16 +1022,30 @@ public static String getSetterName(String propertyName) {
10221022
* @param name The name of the method
10231023
* @param args The arguments
10241024
* @return true if it is a javabean property getter
1025+
* @deprecated use {@link #isGetter(String, Class, Class[])} instead because this method has a defect for "is.." method with Boolean return types.
10251026
*/
10261027
public static boolean isGetter(String name, Class<?>[] args) {
1028+
return isGetter(name, boolean.class, args);
1029+
}
1030+
1031+
/**
1032+
* Returns true if the name of the method specified and the number of arguments make it a javabean property getter.
1033+
* The name is assumed to be a valid Java method name, that is not verified.
1034+
*
1035+
* @param name The name of the method
1036+
* @param returnType The return type of the method
1037+
* @param args The arguments
1038+
* @return true if it is a javabean property getter
1039+
*/
1040+
public static boolean isGetter(String name, Class returnType, Class<?>[] args) {
10271041
if (!StringUtils.hasText(name) || args == null)return false;
10281042
if (args.length != 0)return false;
10291043

10301044
if (name.startsWith("get")) {
10311045
name = name.substring(3);
10321046
if (isPropertyMethodSuffix(name)) return true;
10331047
}
1034-
else if (name.startsWith("is")) {
1048+
else if (name.startsWith("is") && returnType == boolean.class) {
10351049
name = name.substring(2);
10361050
if (isPropertyMethodSuffix(name)) return true;
10371051
}

grails-core/src/main/groovy/org/grails/compiler/injection/GrailsASTUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ public static MethodNode addDelegateInstanceMethod(ClassNode classNode, Expressi
263263
if (classNode.hasDeclaredMethod(methodName, copyParameters(parameterTypes, genericsPlaceholders))) {
264264
return null;
265265
}
266-
String propertyName = GrailsClassUtils.getPropertyForGetter(methodName);
266+
String propertyName = GrailsClassUtils.getPropertyForGetter(methodName, declaredMethod.getReturnType().getTypeClass());
267267
if (propertyName != null && parameterTypes.length == 0 && classNode.hasProperty(propertyName)) {
268268
return null;
269269
}

grails-core/src/main/groovy/org/grails/core/metaclass/BaseApiProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private boolean isNotExcluded(Method method, final int modifiers) {
131131
boolean isStatic = Modifier.isStatic(modifiers);
132132

133133
// skip plain setters/getters by default for instance methods (non-static)
134-
if (!isStatic && (GrailsClassUtils.isSetter(name, method.getParameterTypes()) || GrailsClassUtils.isGetter(name, method.getParameterTypes()))) {
134+
if (!isStatic && (GrailsClassUtils.isSetter(name, method.getParameterTypes()) || GrailsClassUtils.isGetter(name, method.getReturnType(), method.getParameterTypes()))) {
135135
return false;
136136
}
137137

grails-core/src/main/groovy/org/grails/core/util/ClassPropertyFetcher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public void doWith(CachedMethod method) throws IllegalArgumentException,
130130
return;
131131
}
132132

133-
String propertyName = GrailsClassUtils.getPropertyForGetter(method.getName());
133+
String propertyName = GrailsClassUtils.getPropertyForGetter(method.getName(), method.getReturnType());
134134
if(propertyName == null || propertyName.indexOf('$') != -1) {
135135
return;
136136
}

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

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,18 @@ class CommandObjectConstraintGettersSpec extends Specification {
5252
}
5353

5454

55-
void 'ensure only public non-static properties with getter and setter are constrained properties'() {
55+
void 'ensure only public non-static properties with getter are constrained properties'() {
5656
MethodPropertiesCommand command = new MethodPropertiesCommand()
5757

5858
when: 'empty command with method properties is validated'
5959
command.validate()
6060

6161
//anotherPublicProperty did not error because it is boolean which defaults to false
62-
then: 'only public with getter and setter should fail'
62+
then: 'only public with getter should fail'
6363
command.hasErrors()
6464
command.errors['booleanPublicProperty']?.code == 'nullable'
65-
command.errors.getErrorCount() == 1
65+
command.errors['getterOnly']?.code == 'nullable'
66+
command.errors.getErrorCount() == 2
6667
}
6768

6869

@@ -71,9 +72,10 @@ class CommandObjectConstraintGettersSpec extends Specification {
7172
Map constrainedProperties = MethodPropertiesCommand.getConstraintsMap()
7273

7374
then: 'only public property with getter and setter should fail'
74-
constrainedProperties.size() == 2
75+
constrainedProperties.size() == 3
7576
constrainedProperties.containsKey('anotherPublicProperty')
7677
constrainedProperties.containsKey('booleanPublicProperty')
78+
constrainedProperties.containsKey('getterOnly')
7779
}
7880

7981
// COMMAND OBJECT WITH SUPER CLASS
@@ -104,7 +106,7 @@ class CommandObjectConstraintGettersSpec extends Specification {
104106
}
105107

106108

107-
void 'ensure only public non-static inherited properties with getter and setter are constrained properties'() {
109+
void 'ensure only public non-static inherited properties with getter are constrained properties'() {
108110
InheritedMethodPropertiesCommand command = new InheritedMethodPropertiesCommand()
109111
when: 'empty command with method properties is validated'
110112
command.validate()
@@ -113,18 +115,20 @@ class CommandObjectConstraintGettersSpec extends Specification {
113115
then: 'only public with getter and setter should fail'
114116
command.hasErrors()
115117
command.errors['booleanPublicProperty']?.code == 'nullable'
116-
command.errors.getErrorCount() == 1
118+
command.errors['getterOnly']?.code == 'nullable'
119+
command.errors.getErrorCount() == 2
117120
}
118121

119122

120-
void 'ensure constrained inherited method properties are only public ones with both getter and setter'() {
123+
void 'ensure constrained inherited method properties are only public ones with getter'() {
121124
when: 'constrained properties map is get from child class'
122125
Map constrainedProperties = InheritedMethodPropertiesCommand.getConstraintsMap()
123126

124127
then: 'only public with getter and setter should be there'
125-
constrainedProperties.size() == 2
128+
constrainedProperties.size() == 3
126129
constrainedProperties.containsKey('anotherPublicProperty')
127130
constrainedProperties.containsKey('booleanPublicProperty')
131+
constrainedProperties.containsKey('getterOnly')
128132
}
129133

130134
// COMMAND OBJECT WITH TRAIT
@@ -155,7 +159,7 @@ class CommandObjectConstraintGettersSpec extends Specification {
155159
}
156160

157161

158-
void 'ensure only public non-static properties from trait with getter and setter are constrained properties'() {
162+
void 'ensure only public non-static properties from trait with getter are constrained properties'() {
159163
TraitMethodPropertiesCommand command = new TraitMethodPropertiesCommand()
160164
when: 'empty command with simple properties is validated'
161165
command.validate()
@@ -164,23 +168,25 @@ class CommandObjectConstraintGettersSpec extends Specification {
164168
then: 'all should fail on nullable constraint'
165169
command.hasErrors()
166170
command.errors['booleanPublicProperty']?.code == 'nullable'
167-
command.errors.getErrorCount() == 1
171+
command.errors['getterOnly']?.code == 'nullable'
172+
command.errors.getErrorCount() == 2
168173
}
169174

170175

171-
void 'ensure constrained method properties from trait are only public ones with both getter and setter'() {
176+
void 'ensure constrained method properties from trait are only public ones with getter'() {
172177
when: 'constrained properties map is get'
173178
Map constrainedProperties = TraitMethodPropertiesCommand.getConstraintsMap()
174179

175180
then: 'only 4 defined public properties are there'
176-
constrainedProperties.size() == 2
181+
constrainedProperties.size() == 3
177182
constrainedProperties.containsKey('anotherPublicProperty')
178183
constrainedProperties.containsKey('booleanPublicProperty')
184+
constrainedProperties.containsKey('getterOnly')
179185
}
180186

181187
// BOOL METHODS COMMAND OBJECT
182188

183-
void 'ensure only public non-static bool properties with getter and setter are constrained properties'() {
189+
void 'ensure only public non-static bool properties with getter are constrained properties'() {
184190
BoolMethodPropertiesCommand command = new BoolMethodPropertiesCommand()
185191
when: 'empty command with method properties is validated'
186192
command.validate()
@@ -189,23 +195,25 @@ class CommandObjectConstraintGettersSpec extends Specification {
189195
then: 'only public with getter and setter should fail'
190196
command.hasErrors()
191197
command.errors['booleanPublicProperty']?.code == 'nullable'
192-
command.errors.getErrorCount() == 1
198+
command.errors['getterOnly']?.code == 'nullable'
199+
command.errors.getErrorCount() == 2
193200
}
194201

195202

196-
void 'ensure constrained bool method properties are only public ones with both getter and setter'() {
203+
void 'ensure constrained bool method properties are only public ones with getter'() {
197204
when: 'constrained properties map is get'
198205
Map constrainedProperties = BoolMethodPropertiesCommand.getConstraintsMap()
199206

200207
then: 'only public property with getter and setter should fail'
201-
constrainedProperties.size() == 2
208+
constrainedProperties.size() == 3
202209
constrainedProperties.containsKey('anotherPublicProperty')
203210
constrainedProperties.containsKey('booleanPublicProperty')
211+
constrainedProperties.containsKey('getterOnly')
204212
}
205213

206214
// BOOL COMMAND OBJECT WITH SUPER CLASS
207215

208-
void 'ensure only public non-static inherited bool properties with getter and setter are constrained properties'() {
216+
void 'ensure only public non-static inherited bool properties with getter are constrained properties'() {
209217
InheritedBoolMethodPropertiesCommand command = new InheritedBoolMethodPropertiesCommand()
210218
when: 'empty command with method properties is validated'
211219
command.validate()
@@ -214,23 +222,25 @@ class CommandObjectConstraintGettersSpec extends Specification {
214222
then: 'only public with getter and setter should fail'
215223
command.hasErrors()
216224
command.errors['booleanPublicProperty']?.code == 'nullable'
217-
command.errors.getErrorCount() == 1
225+
command.errors['getterOnly']?.code == 'nullable'
226+
command.errors.getErrorCount() == 2
218227
}
219228

220-
void 'ensure constrained inherited bool method properties are only public ones with both getter and setter'() {
229+
void 'ensure constrained inherited bool method properties are only public ones with getter'() {
221230
when: 'constrained properties map is get from child class'
222231
Map constrainedProperties = InheritedBoolMethodPropertiesCommand.getConstraintsMap()
223232

224233
then: 'only public with getter and setter should be there'
225-
constrainedProperties.size() == 2
234+
constrainedProperties.size() == 3
226235
constrainedProperties.containsKey('anotherPublicProperty')
227236
constrainedProperties.containsKey('booleanPublicProperty')
237+
constrainedProperties.containsKey('getterOnly')
228238
}
229239

230240
// BOOL COMMAND OBJECT WITH TRAIT
231241

232242

233-
void 'ensure only public non-static bool properties from trait with getter and setter are constrained properties'() {
243+
void 'ensure only public non-static bool properties from trait with getter are constrained properties'() {
234244
TraitBoolMethodPropertiesCommand command = new TraitBoolMethodPropertiesCommand()
235245
when: 'empty command with simple properties is validated'
236246
command.validate()
@@ -239,17 +249,19 @@ class CommandObjectConstraintGettersSpec extends Specification {
239249
then: 'all should fail on nullable constraint'
240250
command.hasErrors()
241251
command.errors['booleanPublicProperty']?.code == 'nullable'
242-
command.errors.getErrorCount() == 1
252+
command.errors['getterOnly']?.code == 'nullable'
253+
command.errors.getErrorCount() == 2
243254
}
244255

245-
void 'ensure constrained bool method properties from trait are only public ones with both getter and setter'() {
256+
void 'ensure constrained bool method properties from trait are only public ones with getter'() {
246257
when: 'constrained properties map is get'
247258
Map constrainedProperties = TraitBoolMethodPropertiesCommand.getConstraintsMap()
248259

249260
then: 'only 4 defined public properties are there'
250-
constrainedProperties.size() == 2
261+
constrainedProperties.size() == 3
251262
constrainedProperties.containsKey('anotherPublicProperty')
252263
constrainedProperties.containsKey('booleanPublicProperty')
264+
constrainedProperties.containsKey('getterOnly')
253265
}
254266
}
255267

grails-validation/src/main/groovy/org/grails/validation/DefaultConstraintEvaluator.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -409,12 +409,8 @@ else if(writeMethod == null || (Modifier.isTransient(readMethod.getModifiers()))
409409
for (Method method : clazz.getDeclaredMethods()) {
410410
if (GrailsClassUtils.isPropertyGetter(method)) {
411411
String propertyName = GrailsClassUtils.getPropertyForGetter(method.getName(), method.getReturnType());
412-
if (!ignoredProperties.contains(propertyName)) {
413-
System.out.println(method.getName());
414-
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(theClass, propertyName);
415-
if (descriptor != null && descriptor.getWriteMethod() != null) {
416-
propertyMap.put(propertyName, method);
417-
}
412+
if (propertyName != null && !ignoredProperties.contains(propertyName)) {
413+
propertyMap.put(propertyName, method);
418414
}
419415
}
420416
}

0 commit comments

Comments
 (0)