Skip to content

Changes to support Micronaut processors as a Native Image#12449

Merged
graemerocher merged 6 commits into
5.0.xfrom
micronautc-processors-native-image-support
Mar 9, 2026
Merged

Changes to support Micronaut processors as a Native Image#12449
graemerocher merged 6 commits into
5.0.xfrom
micronautc-processors-native-image-support

Conversation

@graemerocher

Copy link
Copy Markdown
Contributor

Summary

Verification

  • ./gradlew :micronaut-core:test --tests 'io.micronaut.core.io.service.SoftServiceLoaderTest' :micronaut-core-processor:compileJava :micronaut-inject-java:compileJava

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Micronaut’s annotation processing/visitor service loading to better support execution in native-image contexts (e.g., by using an alternative classloader strategy and a ServiceLoader fallback), and enhances SoftServiceLoader instantiation behavior with a MethodHandle-first approach and reflection fallback.

Changes:

  • Add optional context-classloader-based service loading (behind micronaut.processing.use.context.classloader) and JDK ServiceLoader fallbacks for visitors/mappers/transformers.
  • Make SoftServiceLoader instantiate services via MethodHandles first, with reflection fallback when access via MethodHandles is not possible.
  • Add a regression test covering reflection fallback when MethodHandles cannot access a constructor.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
inject-java/src/main/java/io/micronaut/annotation/processing/TypeElementVisitorProcessor.java Adds context classloader selection and a ServiceLoader fallback for TypeElementVisitor discovery; adjusts supported-options detection and deduping.
core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java Introduces shared instantiation helper using MethodHandles first with reflection fallback.
core/src/test/java/io/micronaut/core/io/service/SoftServiceLoaderTest.java Adds test ensuring reflection fallback is used when MethodHandles cannot access a constructor.
core-processor/src/main/java/io/micronaut/inject/visitor/BeanElementVisitorLoader.java Adds context classloader selection and ServiceLoader fallback for BeanElementVisitor loading.
core-processor/src/main/java/io/micronaut/inject/annotation/AbstractAnnotationMetadataBuilder.java Switches mapper/transformer/remapper/validator loading to use context classloader selection and ServiceLoader fallback.

@graemerocher

Copy link
Copy Markdown
Contributor Author

@copilot create a PR that targets this PR and addresses you comments

Copilot AI commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

@graemerocher I've opened a new pull request, #12451, to work on those changes. Once the pull request is ready, I'll request review from you.

…zy first-service loading, handle InaccessibleObjectException in reflection fallback, preserve order in visitor dedup (#12451)

* Initial plan

* Address PR review comments: centralize property constant, lazy first-service load, InaccessibleObjectException handling, LinkedHashMap for dedup

Co-authored-by: graemerocher <66626+graemerocher@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: graemerocher <66626+graemerocher@users.noreply.github.com>
@graemerocher graemerocher added the type: improvement A minor improvement to an existing feature label Mar 9, 2026
Copilot AI review requested due to automatic review settings March 9, 2026 11:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment thread core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java Outdated
@graemerocher

Copy link
Copy Markdown
Contributor Author

@copilot create a new PR addressing the comments

Copilot AI commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

@graemerocher I've opened a new pull request, #12453, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 9, 2026 14:14
… transparency in service loading (#12453)

* Address review feedback: iterator-based ServiceLoader fallbacks, preserve exception cause, update StaticDefinition Javadoc

Co-authored-by: graemerocher <66626+graemerocher@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: graemerocher <66626+graemerocher@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 9, 2026 13:32
@graemerocher graemerocher requested a review from dstepanov March 9, 2026 13:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Comment on lines +47 to +50
def previous = Thread.currentThread().contextClassLoader
def propertyName = "micronaut.processing.use.context.classloader"
def previousProperty = System.getProperty(propertyName)

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test hard-codes the system property name ("micronaut.processing.use.context.classloader") even though the code introduces VisitorContext.MICRONAUT_PROCESSING_USE_CONTEXT_CLASSLOADER. Using the constant here would prevent drift if the option key changes in the future.

Copilot uses AI. Check for mistakes.
Comment on lines +181 to +201
for (ServiceDefinition<S> definition : SoftServiceLoader.load(serviceType, classLoader).disableFork()) {
try {
if (definition.isPresent()) {
return Optional.of(definition.load());
}
} catch (Throwable e) {
if (e instanceof VirtualMachineError virtualMachineError) {
throw virtualMachineError;
}
}
}
Iterator<ServiceLoader.Provider<S>> it = ServiceLoader.load(serviceType, classLoader).stream().iterator();
while (it.hasNext()) {
try {
return Optional.of(it.next().get());
} catch (Throwable e) {
if (e instanceof VirtualMachineError virtualMachineError) {
throw virtualMachineError;
}
}
}

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadFirstService catches and ignores any throwable from ServiceDefinition#load() / provider creation (except VirtualMachineError). Previously, a failing first AnnotatedElementValidator would surface immediately; now it can be silently skipped, potentially disabling validation with no signal. Consider only ignoring known “soft” failures (e.g. missing classes) and otherwise rethrowing or at least recording/reporting the error.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +75
Iterator<ServiceLoader.Provider<BeanElementVisitor>> iterator = ServiceLoader.load(BeanElementVisitor.class, classLoader).stream().iterator();
while (iterator.hasNext()) {
try {
BeanElementVisitor<?> visitor = iterator.next().get();
if (visitor.isEnabled()) {
visitors.add(visitor);
}
} catch (Throwable e) {
if (e instanceof VirtualMachineError virtualMachineError) {
throw virtualMachineError;
}
}

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ServiceLoader fallback loop swallows all throwables (except VirtualMachineError). If a BeanElementVisitor is present but misconfigured (e.g. ServiceConfigurationError) this will be silently ignored and visitor execution may be partially/entirely disabled without any indication. Consider rethrowing ServiceConfigurationError/LinkageError (or otherwise surfacing the failure) to avoid masking real configuration issues.

Copilot uses AI. Check for mistakes.
@sonarqubecloud

sonarqubecloud Bot commented Mar 9, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
53.1% Coverage on New Code (required ≥ 70%)

See analysis details on SonarQube Cloud

@graemerocher graemerocher merged commit c0b2f34 into 5.0.x Mar 9, 2026
13 of 14 checks passed
@graemerocher graemerocher deleted the micronautc-processors-native-image-support branch March 9, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: improvement A minor improvement to an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants