This is an automated email from the ASF dual-hosted git repository. pkarwasz pushed a commit to branch 2.25.x in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 65036cb2f27b73439491e3c2fbaa628396146b04 Author: Piotr P. Karwasz <[email protected]> AuthorDate: Thu Jul 3 16:55:32 2025 +0200 fix: Fix Java type for annotated array parameters (#3797) This update fixes the GraalVM reachability metadata generation for methods with annotated array parameters, such as `@Nullable String[]`. Previously, the code computed the fully qualified class name for the parameter using the **raw** type, which retained the annotations (e.g., `@org.jspecify.annotations.Nullable java.lang.String`). This resulted in incorrect metadata that was ignored by GraalVM. The issue is resolved by transforming the `DeclaredType` into a `TypeElement`, effectively removing any annotations, and then calling `getQualifiedName()` to correctly generate the fully qualified class name without annotations. --- .../plugins/processor/GraalVmProcessorTest.java | 24 +++++++++-- .../GraalVmProcessorTest/java/FakeConverter.java | 46 ++++++++++++++++++++++ .../config/plugins/processor/GraalVmProcessor.java | 4 +- .../.2.x.x/3796_annotated-array-parameters.xml | 12 ++++++ 4 files changed, 81 insertions(+), 5 deletions(-) diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/GraalVmProcessorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/GraalVmProcessorTest.java index 9bdbcad8dd..957bb3228c 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/GraalVmProcessorTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/GraalVmProcessorTest.java @@ -103,6 +103,18 @@ class GraalVmProcessorTest { private static final Object FAKE_CONSTRAINT_VALIDATOR = onlyNoArgsConstructor(FAKE_CONSTRAINT_VALIDATOR_NAME); private static final String FAKE_PLUGIN_VISITOR_NAME = "example.FakeAnnotations$FakePluginVisitor"; private static final Object FAKE_PLUGIN_VISITOR = onlyNoArgsConstructor(FAKE_PLUGIN_VISITOR_NAME); + private static final String FAKE_CONVERTER_NAME = "example.FakeConverter"; + private static final Object FAKE_CONVERTER = asMap( + "name", + FAKE_CONVERTER_NAME, + "methods", + singletonList(asMap( + "name", + "newInstance", + "parameterTypes", + asList("org.apache.logging.log4j.core.config.Configuration", "java.lang.String[]"))), + "fields", + emptyList()); private static final String GROUP_ID = "groupId"; private static final String ARTIFACT_ID = "artifactId"; @@ -155,7 +167,8 @@ class GraalVmProcessorTest { Arguments.of(FAKE_PLUGIN_BUILDER_NAME, FAKE_PLUGIN_BUILDER), Arguments.of(FAKE_PLUGIN_NESTED_NAME, FAKE_PLUGIN_NESTED), Arguments.of(FAKE_CONSTRAINT_VALIDATOR_NAME, FAKE_CONSTRAINT_VALIDATOR), - Arguments.of(FAKE_PLUGIN_VISITOR_NAME, FAKE_PLUGIN_VISITOR)); + Arguments.of(FAKE_PLUGIN_VISITOR_NAME, FAKE_PLUGIN_VISITOR), + Arguments.of(FAKE_CONVERTER_NAME, FAKE_CONVERTER)); } @ParameterizedTest @@ -168,7 +181,9 @@ class GraalVmProcessorTest { assertThatJson(reachabilityMetadata) .inPath(String.format("$[?(@.name == '%s')]", className)) .isArray() - .contains(json(expectedJson)); + .hasSize(1) + .first() + .isEqualTo(json(expectedJson)); } static Stream<Arguments> reachabilityMetadataPath() { @@ -214,7 +229,7 @@ class GraalVmProcessorTest { } // The generated folder name should be deterministic and based solely on the descriptor content. // If the descriptor changes, this test and the expected folder name must be updated accordingly. - assertThat(reachabilityMetadataFolders).hasSize(1).containsExactly(path.resolve("62162090")); + assertThat(reachabilityMetadataFolders).hasSize(1).containsExactly(path.resolve("72c240aa")); assertThat(reachabilityMetadataFolders.get(0).resolve("reflect-config.json")) .as("Reachability metadata file") .exists(); @@ -250,7 +265,6 @@ class GraalVmProcessorTest { } // Compile the sources - final Path descriptorFilePath = outputDir.resolve("plugins.xml"); final DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>(); final JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, options, null, sources); @@ -260,6 +274,8 @@ class GraalVmProcessorTest { return diagnosticCollector.getDiagnostics().stream() .filter(d -> d.getKind() != Diagnostic.Kind.NOTE) .map(d -> d.getMessage(Locale.ROOT)) + // This message appears when the test runs on JDK 8 + .filter(m -> !"unknown enum constant java.lang.annotation.ElementType.MODULE".equals(m)) .collect(Collectors.toList()); } } diff --git a/log4j-core-test/src/test/resources/GraalVmProcessorTest/java/FakeConverter.java b/log4j-core-test/src/test/resources/GraalVmProcessorTest/java/FakeConverter.java new file mode 100644 index 0000000000..0b15cb4ecc --- /dev/null +++ b/log4j-core-test/src/test/resources/GraalVmProcessorTest/java/FakeConverter.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you 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 + * + * http://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 example; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.pattern.ConverterKeys; +import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; +import org.apache.logging.log4j.core.pattern.PatternConverter; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +@Plugin(name = "FakePatternConverter", category = PatternConverter.CATEGORY) +@ConverterKeys({"f", "fake"}) +public final class FakeConverter extends LogEventPatternConverter { + + private FakeConverter(@Nullable final Configuration config, @Nullable final String[] options) { + super("Fake", "fake"); + } + + public static FakeConverter newInstance( + @Nullable final Configuration config, @Nullable final String[] options) { + return new FakeConverter(config, options); + } + + @Override + public void format(LogEvent event, StringBuilder toAppendTo) { + toAppendTo.append("FakeConverter: ").append(event.getMessage().getFormattedMessage()); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/GraalVmProcessor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/GraalVmProcessor.java index e6178f2a17..a5ba7ba61c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/GraalVmProcessor.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/GraalVmProcessor.java @@ -300,7 +300,9 @@ public class GraalVmProcessor extends AbstractProcessor { @Override public @Nullable String visitDeclared(final DeclaredType t, final Void unused) { - return processingEnv.getTypeUtils().erasure(t).toString(); + return safeCast(t.asElement(), TypeElement.class) + .getQualifiedName() + .toString(); } }, null); diff --git a/src/changelog/.2.x.x/3796_annotated-array-parameters.xml b/src/changelog/.2.x.x/3796_annotated-array-parameters.xml new file mode 100644 index 0000000000..5be57fe641 --- /dev/null +++ b/src/changelog/.2.x.x/3796_annotated-array-parameters.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<entry xmlns="https://logging.apache.org/xml/ns" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + https://logging.apache.org/xml/ns + https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" + type="fixed"> + <issue id="3796" link="https://github.com/apache/logging-log4j2/issues/3796"/> + <description format="asciidoc"> + Fix GraalVM reachability metadata generation for methods with annotated array type parameters, such as `@Nullable String[]`. + </description> +</entry>
