diff --git a/framework-platform/framework-platform.gradle b/framework-platform/framework-platform.gradle
index 998c491855..804c6fa58a 100644
--- a/framework-platform/framework-platform.gradle
+++ b/framework-platform/framework-platform.gradle
@@ -34,6 +34,7 @@ dependencies {
api("com.google.protobuf:protobuf-java-util:4.28.3")
api("com.h2database:h2:2.3.232")
api("com.jayway.jsonpath:json-path:2.9.0")
+ api("com.networknt:json-schema-validator:1.5.3")
api("com.oracle.database.jdbc:ojdbc11:21.9.0.0")
api("com.rometools:rome:1.19.0")
api("com.squareup.okhttp3:mockwebserver:3.14.9")
diff --git a/spring-core/spring-core.gradle b/spring-core/spring-core.gradle
index a08d0e1667..ebad4fa180 100644
--- a/spring-core/spring-core.gradle
+++ b/spring-core/spring-core.gradle
@@ -104,6 +104,7 @@ dependencies {
testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
testImplementation("org.mockito:mockito-core")
+ testImplementation("com.networknt:json-schema-validator");
testImplementation("org.skyscreamer:jsonassert")
testImplementation("org.xmlunit:xmlunit-assertj")
testImplementation("org.xmlunit:xmlunit-matchers")
diff --git a/spring-core/src/main/java/org/springframework/aot/nativex/NativeConfigurationWriter.java b/spring-core/src/main/java/org/springframework/aot/nativex/NativeConfigurationWriter.java
index 5ef7d21e26..d0886760c4 100644
--- a/spring-core/src/main/java/org/springframework/aot/nativex/NativeConfigurationWriter.java
+++ b/spring-core/src/main/java/org/springframework/aot/nativex/NativeConfigurationWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,11 +18,7 @@ package org.springframework.aot.nativex;
import java.util.function.Consumer;
-import org.springframework.aot.hint.ProxyHints;
-import org.springframework.aot.hint.ReflectionHints;
-import org.springframework.aot.hint.ResourceHints;
import org.springframework.aot.hint.RuntimeHints;
-import org.springframework.aot.hint.SerializationHints;
/**
* Write {@link RuntimeHints} as GraalVM native configuration.
@@ -30,8 +26,9 @@ import org.springframework.aot.hint.SerializationHints;
* @author Sebastien Deleuze
* @author Stephane Nicoll
* @author Janne Valkealahti
+ * @author Brian Clozel
* @since 6.0
- * @see Native Image Build Configuration
+ * @see Native Image Build Configuration
*/
public abstract class NativeConfigurationWriter {
@@ -40,24 +37,21 @@ public abstract class NativeConfigurationWriter {
* @param hints the hints to handle
*/
public void write(RuntimeHints hints) {
- if (hints.serialization().javaSerializationHints().findAny().isPresent()) {
- writeSerializationHints(hints.serialization());
- }
- if (hints.proxies().jdkProxyHints().findAny().isPresent()) {
- writeProxyHints(hints.proxies());
- }
- if (hints.reflection().typeHints().findAny().isPresent()) {
- writeReflectionHints(hints.reflection());
- }
- if (hints.resources().resourcePatternHints().findAny().isPresent() ||
- hints.resources().resourceBundleHints().findAny().isPresent()) {
- writeResourceHints(hints.resources());
- }
- if (hints.jni().typeHints().findAny().isPresent()) {
- writeJniHints(hints.jni());
+ if (hasAnyHint(hints)) {
+ writeTo("reachability-metadata.json",
+ writer -> new RuntimeHintsWriter().write(writer, hints));
}
}
+ private boolean hasAnyHint(RuntimeHints hints) {
+ return (hints.serialization().javaSerializationHints().findAny().isPresent()
+ || hints.proxies().jdkProxyHints().findAny().isPresent()
+ || hints.reflection().typeHints().findAny().isPresent()
+ || hints.resources().resourcePatternHints().findAny().isPresent()
+ || hints.resources().resourceBundleHints().findAny().isPresent()
+ || hints.jni().typeHints().findAny().isPresent());
+ }
+
/**
* Write the specified GraalVM native configuration file, using the
* provided {@link BasicJsonWriter}.
@@ -66,29 +60,4 @@ public abstract class NativeConfigurationWriter {
*/
protected abstract void writeTo(String fileName, Consumer writer);
- private void writeSerializationHints(SerializationHints hints) {
- writeTo("serialization-config.json", writer ->
- SerializationHintsWriter.INSTANCE.write(writer, hints));
- }
-
- private void writeProxyHints(ProxyHints hints) {
- writeTo("proxy-config.json", writer ->
- ProxyHintsWriter.INSTANCE.write(writer, hints));
- }
-
- private void writeReflectionHints(ReflectionHints hints) {
- writeTo("reflect-config.json", writer ->
- ReflectionHintsWriter.INSTANCE.write(writer, hints));
- }
-
- private void writeResourceHints(ResourceHints hints) {
- writeTo("resource-config.json", writer ->
- ResourceHintsWriter.INSTANCE.write(writer, hints));
- }
-
- private void writeJniHints(ReflectionHints hints) {
- writeTo("jni-config.json", writer ->
- ReflectionHintsWriter.INSTANCE.write(writer, hints));
- }
-
}
diff --git a/spring-core/src/main/java/org/springframework/aot/nativex/ProxyHintsWriter.java b/spring-core/src/main/java/org/springframework/aot/nativex/ProxyHintsWriter.java
deleted file mode 100644
index 51cd3132ef..0000000000
--- a/spring-core/src/main/java/org/springframework/aot/nativex/ProxyHintsWriter.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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 org.springframework.aot.nativex;
-
-import java.util.Comparator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import org.springframework.aot.hint.JdkProxyHint;
-import org.springframework.aot.hint.ProxyHints;
-import org.springframework.aot.hint.TypeReference;
-
-/**
- * Write {@link JdkProxyHint}s contained in a {@link ProxyHints} to the JSON
- * output expected by the GraalVM {@code native-image} compiler, typically named
- * {@code proxy-config.json}.
- *
- * @author Sebastien Deleuze
- * @author Stephane Nicoll
- * @author Brian Clozel
- * @since 6.0
- * @see Dynamic Proxy in Native Image
- * @see Native Image Build Configuration
- */
-class ProxyHintsWriter {
-
- public static final ProxyHintsWriter INSTANCE = new ProxyHintsWriter();
-
- private static final Comparator JDK_PROXY_HINT_COMPARATOR =
- (left, right) -> {
- String leftSignature = left.getProxiedInterfaces().stream()
- .map(TypeReference::getCanonicalName).collect(Collectors.joining(","));
- String rightSignature = right.getProxiedInterfaces().stream()
- .map(TypeReference::getCanonicalName).collect(Collectors.joining(","));
- return leftSignature.compareTo(rightSignature);
- };
-
- public void write(BasicJsonWriter writer, ProxyHints hints) {
- writer.writeArray(hints.jdkProxyHints().sorted(JDK_PROXY_HINT_COMPARATOR)
- .map(this::toAttributes).toList());
- }
-
- private Map toAttributes(JdkProxyHint hint) {
- Map attributes = new LinkedHashMap<>();
- handleCondition(attributes, hint);
- attributes.put("interfaces", hint.getProxiedInterfaces());
- return attributes;
- }
-
- private void handleCondition(Map attributes, JdkProxyHint hint) {
- if (hint.getReachableType() != null) {
- Map conditionAttributes = new LinkedHashMap<>();
- conditionAttributes.put("typeReachable", hint.getReachableType());
- attributes.put("condition", conditionAttributes);
- }
- }
-
-}
diff --git a/spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsWriter.java b/spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsAttributes.java
similarity index 57%
rename from spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsWriter.java
rename to spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsAttributes.java
index 3d678b0d85..4d7b2b27a4 100644
--- a/spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsWriter.java
+++ b/spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsAttributes.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2023 the original author or authors.
+ * Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,48 +16,72 @@
package org.springframework.aot.nativex;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.springframework.aot.hint.ConditionalHint;
import org.springframework.aot.hint.ExecutableHint;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.FieldHint;
+import org.springframework.aot.hint.JdkProxyHint;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.ReflectionHints;
+import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeHint;
+import org.springframework.aot.hint.TypeReference;
import org.springframework.lang.Nullable;
/**
- * Write {@link ReflectionHints} to the JSON output expected by the GraalVM
- * {@code native-image} compiler, typically named {@code reflect-config.json}
- * or {@code jni-config.json}.
+ * Collect {@link ReflectionHints} as map attributes ready for JSON serialization for the GraalVM
+ * {@code native-image} compiler.
*
* @author Sebastien Deleuze
* @author Stephane Nicoll
* @author Janne Valkealahti
- * @since 6.0
- * @see Reflection Use in Native Images
- * @see Java Native Interface (JNI) in Native Image
- * @see Native Image Build Configuration
+ * @see Reflection Use in Native Images
+ * @see Java Native Interface (JNI) in Native Image
+ * @see Native Image Build Configuration
*/
-class ReflectionHintsWriter {
+class ReflectionHintsAttributes {
- public static final ReflectionHintsWriter INSTANCE = new ReflectionHintsWriter();
+ private static final Comparator JDK_PROXY_HINT_COMPARATOR =
+ (left, right) -> {
+ String leftSignature = left.getProxiedInterfaces().stream()
+ .map(TypeReference::getCanonicalName).collect(Collectors.joining(","));
+ String rightSignature = right.getProxiedInterfaces().stream()
+ .map(TypeReference::getCanonicalName).collect(Collectors.joining(","));
+ return leftSignature.compareTo(rightSignature);
+ };
- public void write(BasicJsonWriter writer, ReflectionHints hints) {
- writer.writeArray(hints.typeHints()
+ public List