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 9bdbcad8dd9..957bb3228cd 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 @@ static Stream containsSpecificEntries() { 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 @@ void containsSpecificEntries(String className, Object expectedJson) throws IOExc assertThatJson(reachabilityMetadata) .inPath(String.format("$[?(@.name == '%s')]", className)) .isArray() - .contains(json(expectedJson)); + .hasSize(1) + .first() + .isEqualTo(json(expectedJson)); } static Stream reachabilityMetadataPath() { @@ -214,7 +229,7 @@ void whenNoGroupIdAndArtifactId_thenWarningIsPrinted(@TempDir(cleanup = CleanupM } // 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 @@ private static List generateDescriptor( } // Compile the sources - final Path descriptorFilePath = outputDir.resolve("plugins.xml"); final DiagnosticCollector diagnosticCollector = new DiagnosticCollector<>(); final JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, options, null, sources); @@ -260,6 +274,8 @@ private static List generateDescriptor( 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 00000000000..0b15cb4ecc1 --- /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 e6178f2a17e..a5ba7ba61c5 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 String visitArray(final ArrayType t, @Nullable Void unused) { @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 00000000000..5be57fe6418 --- /dev/null +++ b/src/changelog/.2.x.x/3796_annotated-array-parameters.xml @@ -0,0 +1,12 @@ + + + + + Fix GraalVM reachability metadata generation for methods with annotated array type parameters, such as `@Nullable String[]`. + +