diff --git a/core-processor/src/main/java/io/micronaut/inject/ast/utils/AstBeanPropertiesUtils.java b/core-processor/src/main/java/io/micronaut/inject/ast/utils/AstBeanPropertiesUtils.java index cf2c0b09d9..54a49e05f4 100644 --- a/core-processor/src/main/java/io/micronaut/inject/ast/utils/AstBeanPropertiesUtils.java +++ b/core-processor/src/main/java/io/micronaut/inject/ast/utils/AstBeanPropertiesUtils.java @@ -89,7 +89,7 @@ public static List resolveBeanProperties(PropertyElementQuery c continue; } String methodName = methodElement.getName(); - if (methodName.contains("$") || methodName.equals("getMetaClass")) { + if (methodName.equals("getMetaClass")) { continue; } boolean isAccessor = canMethodBeUsedForAccess(methodElement, accessKinds, visibility); diff --git a/core/src/main/java/io/micronaut/core/naming/NameUtils.java b/core/src/main/java/io/micronaut/core/naming/NameUtils.java index 0b918523fb..41869276b9 100644 --- a/core/src/main/java/io/micronaut/core/naming/NameUtils.java +++ b/core/src/main/java/io/micronaut/core/naming/NameUtils.java @@ -235,7 +235,8 @@ public static boolean isWriterName(@NonNull String methodName, @NonNull String[] int len = methodName.length(); int prefixLength = writePrefix.length(); if (len > prefixLength && methodName.startsWith(writePrefix)) { - isValid = Character.isUpperCase(methodName.charAt(prefixLength)); + char nextChar = methodName.charAt(prefixLength); + isValid = isValidCharacterAfterReaderWriterPrefix(nextChar); } if (isValid) { @@ -370,7 +371,7 @@ public static boolean isReaderName(@NonNull String methodName, @NonNull String[] int len = methodName.length(); if (len > prefixLength) { char firstVarNameChar = methodName.charAt(prefixLength); - isValid = firstVarNameChar == '_' || firstVarNameChar == '$' || Character.isUpperCase(firstVarNameChar); + isValid = isValidCharacterAfterReaderWriterPrefix(firstVarNameChar); } if (isValid) { @@ -381,6 +382,10 @@ public static boolean isReaderName(@NonNull String methodName, @NonNull String[] return isValid; } + private static boolean isValidCharacterAfterReaderWriterPrefix(char c) { + return c == '_' || c == '$' || Character.isUpperCase(c); + } + /** * Get the equivalent property name for the given getter. * diff --git a/core/src/test/groovy/io/micronaut/core/naming/NameUtilsSpec.groovy b/core/src/test/groovy/io/micronaut/core/naming/NameUtilsSpec.groovy index 26e03fa0a0..f8cf791d23 100644 --- a/core/src/test/groovy/io/micronaut/core/naming/NameUtilsSpec.groovy +++ b/core/src/test/groovy/io/micronaut/core/naming/NameUtilsSpec.groovy @@ -297,6 +297,8 @@ class NameUtilsSpec extends Specification { "isFoo" | ["get"] | true "isfoo" | ["get"] | false "getFoo" | ["get"] | true + 'get$foo' | ["get"] | true + 'get_foo' | ["get"] | true "getfoo" | ["get"] | false "a" | ["get"] | false "foo" | ["with"] | false @@ -322,6 +324,8 @@ class NameUtilsSpec extends Specification { name | prefixes | isValid "foo" | ["set"] | false "setFoo" | ["set"] | true + 'set$foo' | ["set"] | true + 'set_foo' | ["set"] | true "setfoo" | ["set"] | false "a" | ["set"] | false "foo" | ["with"] | false diff --git a/inject-groovy/src/main/groovy/io/micronaut/ast/groovy/visitor/GroovyClassElement.java b/inject-groovy/src/main/groovy/io/micronaut/ast/groovy/visitor/GroovyClassElement.java index 9113f17e28..e0052a821b 100644 --- a/inject-groovy/src/main/groovy/io/micronaut/ast/groovy/visitor/GroovyClassElement.java +++ b/inject-groovy/src/main/groovy/io/micronaut/ast/groovy/visitor/GroovyClassElement.java @@ -112,8 +112,7 @@ public class GroovyClassElement extends AbstractGroovyElement implements Arrayab private static final Predicate JUNK_FIELD_FILTER = m -> { String fieldName = m.getName(); - return fieldName.startsWith("$") || - fieldName.startsWith("__$") || + return fieldName.startsWith("__$") || fieldName.contains("trait$") || fieldName.equals("metaClass") || m.getDeclaringClass().equals(ClassHelper.GROOVY_OBJECT_TYPE) || diff --git a/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/ClassElementSpec.groovy b/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/ClassElementSpec.groovy index 371466f00a..a6a6093e65 100644 --- a/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/ClassElementSpec.groovy +++ b/inject-groovy/src/test/groovy/io/micronaut/inject/visitor/ClassElementSpec.groovy @@ -932,9 +932,13 @@ class SuccessfulTest extends AbstractExample { def allFields = classElement.getEnclosedElements(ElementQuery.ALL_FIELDS) then: props.size() == 3 - props[0].name == "ctx" - props[1].name.contains "dummy" - props[2].name.contains "sharedCtx" + props[0].name == '$spock_sharedField_sharedCtx' + props[1].name == "ctx" + props[2].name.contains "dummy" + allFields.size() == 3 + allFields[0].name == '$spock_sharedField_sharedCtx' + allFields[1].name == "ctx" + allFields[2].name.contains "dummy" } void "test fields selection"() { diff --git a/test-suite-groovy/build.gradle b/test-suite-groovy/build.gradle index 697d3f0d35..19dd0a2380 100644 --- a/test-suite-groovy/build.gradle +++ b/test-suite-groovy/build.gradle @@ -24,6 +24,7 @@ dependencies { testImplementation project(":http-client") testImplementation project(":http-client-jdk") testImplementation project(":inject-groovy") + testImplementation project(":inject-groovy-test") testImplementation project(":http-server-netty") testImplementation project(":jackson-databind") testImplementation project(":runtime") diff --git a/test-suite-groovy/src/test/groovy/io/micronaut/inject/spock/another/InjectFromParentInAnotherPackageCompiledSpec.groovy b/test-suite-groovy/src/test/groovy/io/micronaut/inject/spock/another/InjectFromParentInAnotherPackageCompiledSpec.groovy new file mode 100644 index 0000000000..49927bd2ef --- /dev/null +++ b/test-suite-groovy/src/test/groovy/io/micronaut/inject/spock/another/InjectFromParentInAnotherPackageCompiledSpec.groovy @@ -0,0 +1,25 @@ +package io.micronaut.inject.spock.another + +import io.micronaut.ast.transform.test.AbstractBeanDefinitionSpec +import io.micronaut.inject.BeanDefinition + +class InjectFromParentInAnotherPackageCompiledSpec extends AbstractBeanDefinitionSpec { + + void "test compile spock specification that inherits from already compiled class"() { + given: + def definition = buildBeanDefinition('test.MySpockSpec', ''' +package test + +import io.micronaut.inject.spock.other.AbstractMicronautTestSpec +import io.micronaut.test.extensions.spock.annotation.MicronautTest + +@MicronautTest +class MySpockSpec extends AbstractMicronautTestSpec { + +} +''') + expect: + definition != null + definition.injectedFields.size() == 1 + } +} diff --git a/test-suite-groovy/src/test/groovy/io/micronaut/inject/spock/another/InjectFromParentInAnotherPackageSpec.groovy b/test-suite-groovy/src/test/groovy/io/micronaut/inject/spock/another/InjectFromParentInAnotherPackageSpec.groovy new file mode 100644 index 0000000000..dfb9450724 --- /dev/null +++ b/test-suite-groovy/src/test/groovy/io/micronaut/inject/spock/another/InjectFromParentInAnotherPackageSpec.groovy @@ -0,0 +1,27 @@ +package io.micronaut.inject.spock.another + + +import io.micronaut.core.convert.ConversionService +import io.micronaut.inject.spock.other.AbstractMicronautTestSpec +import io.micronaut.runtime.server.EmbeddedServer +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Shared + +@MicronautTest +class InjectFromParentInAnotherPackageSpec extends AbstractMicronautTestSpec { + + @Inject + EmbeddedServer embeddedServer + + @Inject + @Shared + ConversionService sharedTest + + void "test parent injected"() { + expect:"parent and child beans are injected" + embeddedServer != null + sharedTest != null + sharedFromParent != null + } +} diff --git a/test-suite-groovy/src/test/groovy/io/micronaut/inject/spock/other/AbstractMicronautTestSpec.groovy b/test-suite-groovy/src/test/groovy/io/micronaut/inject/spock/other/AbstractMicronautTestSpec.groovy new file mode 100644 index 0000000000..42431db3cf --- /dev/null +++ b/test-suite-groovy/src/test/groovy/io/micronaut/inject/spock/other/AbstractMicronautTestSpec.groovy @@ -0,0 +1,13 @@ +package io.micronaut.inject.spock.other + +import io.micronaut.context.env.Environment +import jakarta.inject.Inject +import spock.lang.Shared +import spock.lang.Specification + +abstract class AbstractMicronautTestSpec extends Specification { + + @Inject + @Shared + Environment sharedFromParent +}