From 32fd3c4e715b9ea5ad55da8ce5f324cbadf4df29 Mon Sep 17 00:00:00 2001 From: Tim Yates Date: Thu, 2 May 2024 13:12:52 +0100 Subject: [PATCH] fix: KSP processing for package private properties (#10777) --- .../visitor/BeanIntrospectionSpec.groovy | 52 ++++++++++++++ .../inject/visitor/MySuperclass.groovy | 4 ++ .../visitor/PackagePrivateSuperclass.java | 22 ++++++ .../beans/BeanIntrospectionSpec.groovy | 70 +++++++++++++++++++ .../inject/visitor/beans/MySuperclass.java | 4 ++ .../beans/PackagePrivateSuperclass.java | 22 ++++++ .../processing/visitor/KotlinClassElement.kt | 7 +- .../visitor/BeanIntrospectionSpec.groovy | 47 +++++++++++++ .../processing/visitor/MySuperclass.java | 5 ++ .../visitor/PackagePrivateSuperclass.java | 22 ++++++ 10 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 inject-groovy/src/test/groovy/io/micronaut/inject/visitor/MySuperclass.groovy create mode 100644 inject-groovy/src/test/groovy/io/micronaut/inject/visitor/PackagePrivateSuperclass.java create mode 100644 inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/MySuperclass.java create mode 100644 inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/PackagePrivateSuperclass.java create mode 100644 inject-kotlin/src/test/java/io/micronaut/kotlin/processing/visitor/MySuperclass.java create mode 100644 inject-kotlin/src/test/java/io/micronaut/kotlin/processing/visitor/PackagePrivateSuperclass.java diff --git a/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/BeanIntrospectionSpec.groovy b/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/BeanIntrospectionSpec.groovy index a3849875332..29b14ca5350 100644 --- a/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/BeanIntrospectionSpec.groovy +++ b/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/BeanIntrospectionSpec.groovy @@ -2522,4 +2522,56 @@ class Holder { animal.isTypeVariable() } + void "test package private property introspection"() { + when: + def introspection = buildBeanIntrospection('test.Test', ''' +package test + +import io.micronaut.core.annotation.Introspected +import io.micronaut.inject.visitor.MySuperclass + +@Introspected +class Test extends MySuperclass { + + String name +} +''') + then: 'the property in this class is introspected' + introspection.getProperty("name").orElse(null) + + and: 'the public property in the java superclass is introspected' + introspection.getProperty("publicProperty").orElse(null) + + and: 'the private property in the java superclass is not introspected' + !introspection.getProperty("privateProperty").orElse(null) + + and: 'the package private superclass property is not introspected' + !introspection.getProperty("packagePrivateProperty").orElse(null) + } + + void "test package private property introspection in same package"() { + when: + def introspection = buildBeanIntrospection('io.micronaut.inject.visitor.Test', ''' +package io.micronaut.inject.visitor + +import io.micronaut.core.annotation.Introspected + +@Introspected +class Test extends MySuperclass { + + String name +} +''') + then: 'the property in this class is introspected' + introspection.getProperty("name").orElse(null) + + and: 'the public property in the java superclass is introspected' + introspection.getProperty("publicProperty").orElse(null) + + and: 'the private property in the java superclass is not introspected' + !introspection.getProperty("privateProperty").orElse(null) + + and: 'the package private superclass property is introspected, as we are in the same package' + introspection.getProperty("packagePrivateProperty").orElse(null) + } } diff --git a/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/MySuperclass.groovy b/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/MySuperclass.groovy new file mode 100644 index 00000000000..8c13870633c --- /dev/null +++ b/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/MySuperclass.groovy @@ -0,0 +1,4 @@ +package io.micronaut.inject.visitor + +class MySuperclass extends PackagePrivateSuperclass { +} diff --git a/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/PackagePrivateSuperclass.java b/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/PackagePrivateSuperclass.java new file mode 100644 index 00000000000..270bacaf098 --- /dev/null +++ b/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/PackagePrivateSuperclass.java @@ -0,0 +1,22 @@ +package io.micronaut.inject.visitor; + +class PackagePrivateSuperclass { + + String packagePrivateProperty; + + String getPackagePrivateProperty() { + return packagePrivateProperty; + } + + private String privateProperty; + + private String getPrivateProperty() { + return privateProperty; + } + + public String publicProperty; + + public String getPublicProperty() { + return publicProperty; + } +} diff --git a/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/BeanIntrospectionSpec.groovy b/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/BeanIntrospectionSpec.groovy index d0eb81137c4..33d93998bac 100644 --- a/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/BeanIntrospectionSpec.groovy +++ b/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/BeanIntrospectionSpec.groovy @@ -5230,6 +5230,75 @@ class Holder { animal.isTypeVariable() } + void "test package private property introspection"() { + when: + BeanIntrospection introspection = buildBeanIntrospection('test.Test', ''' +package test; + +import io.micronaut.core.annotation.Introspected; +import io.micronaut.inject.visitor.beans.MySuperclass; + +@Introspected +class Test extends MySuperclass { + + private final String name; + + Test(String name) { + this.name = name; + } + + String getName() { + return name; + } +} +''') + then: 'the property in this class is introspected' + introspection.getProperty("name").orElse(null) + + and: 'the public property in the java superclass is introspected' + introspection.getProperty("publicProperty").orElse(null) + + and: 'the private property in the java superclass is not introspected' + !introspection.getProperty("privateProperty").orElse(null) + + and: 'the package private superclass property is not introspected' + !introspection.getProperty("packagePrivateProperty").orElse(null) + } + + void "test package private property introspection in same package"() { + when: + BeanIntrospection introspection = buildBeanIntrospection('io.micronaut.inject.visitor.beans.Test', ''' +package io.micronaut.inject.visitor.beans; + +import io.micronaut.core.annotation.Introspected; + +@Introspected +class Test extends MySuperclass { + + private final String name; + + Test(String name) { + this.name = name; + } + + String getName() { + return name; + } +} +''') + then: 'the property in this class is introspected' + introspection.getProperty("name").orElse(null) + + and: 'the public property in the java superclass is introspected' + introspection.getProperty("publicProperty").orElse(null) + + and: 'the private property in the java superclass is not introspected' + !introspection.getProperty("privateProperty").orElse(null) + + and: 'the package private superclass property is introspected, as we are in the same package' + introspection.getProperty("packagePrivateProperty").orElse(null) + } + void "test private property 1"() { given: BeanIntrospection introspection = buildBeanIntrospection('test.OptionalDoubleHolder', ''' @@ -5255,6 +5324,7 @@ class OptionalDoubleHolder { introspection.getProperty("optionalDouble").get().getType() == OptionalDouble.class introspection.getProperty("optionalDouble").get().hasAnnotation(DecimalMin) } + void "test private property 2"() { given: BeanIntrospection introspection = buildBeanIntrospection('test.OptionalStringHolder', ''' diff --git a/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/MySuperclass.java b/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/MySuperclass.java new file mode 100644 index 00000000000..d639f0ed306 --- /dev/null +++ b/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/MySuperclass.java @@ -0,0 +1,4 @@ +package io.micronaut.inject.visitor.beans; + +public class MySuperclass extends PackagePrivateSuperclass { +} diff --git a/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/PackagePrivateSuperclass.java b/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/PackagePrivateSuperclass.java new file mode 100644 index 00000000000..e930ff78067 --- /dev/null +++ b/inject-java-test/src/test/groovy/io/micronaut/inject/visitor/beans/PackagePrivateSuperclass.java @@ -0,0 +1,22 @@ +package io.micronaut.inject.visitor.beans; + +class PackagePrivateSuperclass { + + String packagePrivateProperty; + + String getPackagePrivateProperty() { + return packagePrivateProperty; + } + + private String privateProperty; + + private String getPrivateProperty() { + return privateProperty; + } + + public String publicProperty; + + public String getPublicProperty() { + return publicProperty; + } +} diff --git a/inject-kotlin/src/main/kotlin/io/micronaut/kotlin/processing/visitor/KotlinClassElement.kt b/inject-kotlin/src/main/kotlin/io/micronaut/kotlin/processing/visitor/KotlinClassElement.kt index bcd38962f5b..53c75460e05 100644 --- a/inject-kotlin/src/main/kotlin/io/micronaut/kotlin/processing/visitor/KotlinClassElement.kt +++ b/inject-kotlin/src/main/kotlin/io/micronaut/kotlin/processing/visitor/KotlinClassElement.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017-2022 original authors + * Copyright 2017-2024 original authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import com.google.devtools.ksp.getDeclaredProperties import com.google.devtools.ksp.getKotlinClassByName import com.google.devtools.ksp.isAbstract import com.google.devtools.ksp.isConstructor +import com.google.devtools.ksp.isJavaPackagePrivate import com.google.devtools.ksp.isPrivate import com.google.devtools.ksp.symbol.ClassKind import com.google.devtools.ksp.symbol.KSAnnotated @@ -64,7 +65,7 @@ import io.micronaut.inject.ast.utils.AstBeanPropertiesUtils import io.micronaut.inject.ast.utils.EnclosedElementsQuery import io.micronaut.inject.processing.ProcessingException import io.micronaut.kotlin.processing.getBinaryName -import java.util.* +import java.util.Optional import java.util.function.Function import java.util.stream.Stream @@ -815,7 +816,7 @@ internal open class KotlinClassElement( } PropertyElement::class.java -> { - classNode.getDeclaredProperties().toList() + classNode.getDeclaredProperties().filter { !it.isJavaPackagePrivate() }.toList() } ConstructorElement::class.java -> { diff --git a/inject-kotlin/src/test/groovy/io/micronaut/kotlin/processing/visitor/BeanIntrospectionSpec.groovy b/inject-kotlin/src/test/groovy/io/micronaut/kotlin/processing/visitor/BeanIntrospectionSpec.groovy index 84f864eac3c..52486f55b0a 100644 --- a/inject-kotlin/src/test/groovy/io/micronaut/kotlin/processing/visitor/BeanIntrospectionSpec.groovy +++ b/inject-kotlin/src/test/groovy/io/micronaut/kotlin/processing/visitor/BeanIntrospectionSpec.groovy @@ -2352,6 +2352,53 @@ class Holder( animal.isTypeVariable() } + void "test package private property introspection"() { + when: + def introspection = buildBeanIntrospection('test.Test', ''' +package test + +import io.micronaut.core.annotation.Introspected +import io.micronaut.kotlin.processing.visitor.MySuperclass + +@Introspected +class Test(val name: String) : MySuperclass() +''') + then: 'the property in this class is introspected' + introspection.getProperty("name").orElse(null) + + and: 'the public property in the java superclass is introspected' + introspection.getProperty("publicProperty").orElse(null) + + and: 'the private property in the java superclass is not introspected' + !introspection.getProperty("privateProperty").orElse(null) + + and: 'the package private superclass property is not introspected' + !introspection.getProperty("packagePrivateProperty").orElse(null) + } + + void "test package private property introspection in same package"() { + when: + def introspection = buildBeanIntrospection('io.micronaut.kotlin.processing.visitor.Test', ''' +package io.micronaut.kotlin.processing.visitor + +import io.micronaut.core.annotation.Introspected + +@Introspected +class Test(val name: String) : MySuperclass() +''') + then: 'the property in this class is introspected' + introspection.getProperty("name").orElse(null) + + and: 'the public property in the java superclass is introspected' + introspection.getProperty("publicProperty").orElse(null) + + and: 'the private property in the java superclass is not introspected' + !introspection.getProperty("privateProperty").orElse(null) + + and: 'the package private superclass property is introspected, as we are in the same package' + introspection.getProperty("packagePrivateProperty").orElse(null) + } + void "test list property"() { given: BeanIntrospection introspection = buildBeanIntrospection('test.Cart', ''' diff --git a/inject-kotlin/src/test/java/io/micronaut/kotlin/processing/visitor/MySuperclass.java b/inject-kotlin/src/test/java/io/micronaut/kotlin/processing/visitor/MySuperclass.java new file mode 100644 index 00000000000..46aac0a46d7 --- /dev/null +++ b/inject-kotlin/src/test/java/io/micronaut/kotlin/processing/visitor/MySuperclass.java @@ -0,0 +1,5 @@ +package io.micronaut.kotlin.processing.visitor; + +public class MySuperclass extends PackagePrivateSuperclass { + +} diff --git a/inject-kotlin/src/test/java/io/micronaut/kotlin/processing/visitor/PackagePrivateSuperclass.java b/inject-kotlin/src/test/java/io/micronaut/kotlin/processing/visitor/PackagePrivateSuperclass.java new file mode 100644 index 00000000000..dd5849e439b --- /dev/null +++ b/inject-kotlin/src/test/java/io/micronaut/kotlin/processing/visitor/PackagePrivateSuperclass.java @@ -0,0 +1,22 @@ +package io.micronaut.kotlin.processing.visitor; + +class PackagePrivateSuperclass { + + String packagePrivateProperty; + + String getPackagePrivateProperty() { + return packagePrivateProperty; + } + + private String privateProperty; + + private String getPrivateProperty() { + return privateProperty; + } + + public String publicProperty; + + public String getPublicProperty() { + return publicProperty; + } +}