Skip to content

Commit

Permalink
Consider getters using get as getter for boolean Kotlin properties.
Browse files Browse the repository at this point in the history
We now additionally consider get-prefixed methods in addition to is-prefixed methods as getters for boolean properties.

Closes #3249
  • Loading branch information
mp911de committed Feb 20, 2025
1 parent 7bab2c7 commit 3c625ca
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,9 @@ private static void collectKotlinProperties(Class<?> beanClass, Collection<KCall

if (member instanceof KProperty<?> property) {

Method getter = ReflectJvmMapping.getJavaGetter(property);
Method setter = property instanceof KMutableProperty<?> kmp ? ReflectJvmMapping.getJavaSetter(kmp) : null;

if (getter == null) {
Type javaType = ReflectJvmMapping.getJavaType(property.getReturnType());
getter = ReflectionUtils.findMethod(beanClass,
javaType == Boolean.TYPE ? "is" : "get" + StringUtils.capitalize(property.getName()));
}

if (getter != null) {
getter = ClassUtils.getMostSpecificMethod(getter, beanClass);
}
Type javaType = ReflectJvmMapping.getJavaType(property.getReturnType());
Method getter = findGetter(beanClass, property, javaType);

if (getter != null && (Modifier.isStatic(getter.getModifiers()) || getter.getParameterCount() != 0)) {
continue;
Expand All @@ -123,6 +114,21 @@ private static void collectKotlinProperties(Class<?> beanClass, Collection<KCall
}
}

private static @Nullable Method findGetter(Class<?> beanClass, KProperty<?> property, Type javaType) {

Method getter = ReflectJvmMapping.getJavaGetter(property);

if (getter == null && javaType == Boolean.TYPE) {
getter = ReflectionUtils.findMethod(beanClass, "is" + StringUtils.capitalize(property.getName()));
}

if (getter == null) {
getter = ReflectionUtils.findMethod(beanClass, "get" + StringUtils.capitalize(property.getName()));
}

return getter != null ? ClassUtils.getMostSpecificMethod(getter, beanClass) : null;
}

private static void collectBasicJavaProperties(Class<?> beanClass, Map<String, PropertyDescriptor> descriptors)
throws IntrospectionException {

Expand Down Expand Up @@ -204,5 +210,7 @@ public void setWriteMethod(@Nullable Method writeMethod) {
public Method getWriteMethod() {
return this.writeMethod;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ void supportsNullableWrapperDateToLocalDateTimeConversion() {
assertThat(excerpt.getBirthdate()).contains(LocalDateTime.of(1967, 1, 9, 0, 0));
}


interface Contact {}

interface CustomerWithLocalDateTime {
Expand Down
40 changes: 40 additions & 0 deletions src/test/kotlin/org/springframework/data/projection/Entities.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.projection

open class KClassWithJavaGetter() {

private var fromOuterSpace: Boolean = false

open fun getFromOuterSpace() = fromOuterSpace

open fun setFromOuterSpace(newValue: Boolean) {
this.fromOuterSpace = newValue
}

}

open class KClassWithIsGetter() {

private var fromOuterSpace: Boolean = false

open fun isFromOuterSpace() = fromOuterSpace

open fun setFromOuterSpace(newValue: Boolean) {
this.fromOuterSpace = newValue
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ class KotlinBeanInfoFactoryUnitTests {
assertThat(pds).hasSize(1).extracting("name").contains("value")
}

@Test // GH-3249
internal fun considersBooleanGetAndIsGetters() {

val isAndGet = BeanUtils.getPropertyDescriptors(KClassWithIsGetter::class.java)
assertThat(isAndGet[0].readMethod.name).isEqualTo("isFromOuterSpace")

val getOnly = BeanUtils.getPropertyDescriptors(KClassWithGetGetter::class.java)
assertThat(getOnly[0].readMethod.name).isEqualTo("getFromOuterSpace")
}

@Test
internal fun determinesInlineClassConsumerProperties() {

Expand Down Expand Up @@ -200,4 +210,29 @@ class KotlinBeanInfoFactoryUnitTests {
class User : AbstractAuditable() {
var name: String? = null
}

open class KClassWithGetGetter() {

private var fromOuterSpace: Boolean = false

open fun getFromOuterSpace() = fromOuterSpace

open fun setFromOuterSpace(newValue: Boolean) {
this.fromOuterSpace = newValue
}
}

open class KClassWithIsGetter() {

private var fromOuterSpace: Boolean = false

open fun isFromOuterSpace() = fromOuterSpace

open fun getFromOuterSpace() = fromOuterSpace

open fun setFromOuterSpace(newValue: Boolean) {
this.fromOuterSpace = newValue
}
}

}

0 comments on commit 3c625ca

Please sign in to comment.