mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-29 18:59:03 +00:00
Migrate to GraalVM metadata format 1.2.0
This commit adapts RuntimeHints to be compatible with v1.2.0 of the GraalVM metadata format. The changes are as follows: * Resources and resource bundles are now defined at the same level. This is transparent to users. * Serialization is no longer a top-level concept, but rather an attribute of a type or proxy. The top-level concept has been deprecated and the relevant methods have been added. Closes gh-36379
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.aot.agent;
|
||||
|
||||
import org.springframework.aot.hint.JavaSerializationHint;
|
||||
import org.springframework.aot.hint.JdkProxyHint;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.ResourceBundleHint;
|
||||
@@ -51,7 +50,9 @@ public enum HintType {
|
||||
/**
|
||||
* Java serialization hint, as described by {@link org.springframework.aot.hint.JavaSerializationHint}.
|
||||
*/
|
||||
JAVA_SERIALIZATION(JavaSerializationHint.class),
|
||||
@Deprecated(since = "7.0.5", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
JAVA_SERIALIZATION(org.springframework.aot.hint.JavaSerializationHint.class),
|
||||
|
||||
/**
|
||||
* JDK proxies hint, as described by {@link org.springframework.aot.hint.ProxyHints#jdkProxyHints()}.
|
||||
|
||||
@@ -27,7 +27,9 @@ import org.jspecify.annotations.Nullable;
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 6.0
|
||||
* @deprecated in favor of {@link TypeHint}
|
||||
*/
|
||||
@Deprecated(since = "7.0.6", forRemoval = true)
|
||||
public final class JavaSerializationHint implements ConditionalHint {
|
||||
|
||||
private final TypeReference type;
|
||||
|
||||
@@ -37,10 +37,13 @@ public final class JdkProxyHint implements ConditionalHint {
|
||||
|
||||
private final @Nullable TypeReference reachableType;
|
||||
|
||||
private final @Nullable Boolean serializable;
|
||||
|
||||
|
||||
private JdkProxyHint(Builder builder) {
|
||||
this.proxiedInterfaces = List.copyOf(builder.proxiedInterfaces);
|
||||
this.reachableType = builder.reachableType;
|
||||
this.serializable = builder.serializable;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,11 +78,21 @@ public final class JdkProxyHint implements ConditionalHint {
|
||||
return this.reachableType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to register this proxy for Java serialization.
|
||||
* @return whether to register this proxy for Java serialization.
|
||||
* @since 7.0.6
|
||||
*/
|
||||
public @Nullable Boolean getSerializable() {
|
||||
return this.serializable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
return (this == other || (other instanceof JdkProxyHint that &&
|
||||
this.proxiedInterfaces.equals(that.proxiedInterfaces) &&
|
||||
Objects.equals(this.reachableType, that.reachableType)));
|
||||
Objects.equals(this.reachableType, that.reachableType) &&
|
||||
Objects.equals(this.serializable, that.serializable)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,6 +110,8 @@ public final class JdkProxyHint implements ConditionalHint {
|
||||
|
||||
private @Nullable TypeReference reachableType;
|
||||
|
||||
private @Nullable Boolean serializable;
|
||||
|
||||
Builder() {
|
||||
this.proxiedInterfaces = new LinkedList<>();
|
||||
}
|
||||
@@ -131,6 +146,17 @@ public final class JdkProxyHint implements ConditionalHint {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify if this proxy should be registered for Java serialization.
|
||||
* @param serializable whether to register this proxy for Java serialization.
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 7.0.6
|
||||
*/
|
||||
public Builder javaSerialization(@Nullable Boolean serializable) {
|
||||
this.serializable = serializable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link JdkProxyHint} based on the state of this builder.
|
||||
* @return a JDK proxy hint
|
||||
|
||||
@@ -231,6 +231,17 @@ public class ReflectionHints {
|
||||
typeHint -> typeHint.withMethod(method.getName(), mapParameters(method), mode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the need for Java Serialization on the specified type.
|
||||
* @param type the type that should be serializable
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 7.0.6
|
||||
*/
|
||||
public ReflectionHints registerJavaSerialization(Class<?> type) {
|
||||
return registerType(TypeReference.of(type),
|
||||
typeHint -> typeHint.withJavaSerialization(true));
|
||||
}
|
||||
|
||||
private List<TypeReference> mapParameters(Executable executable) {
|
||||
return TypeReference.listOf(executable.getParameterTypes());
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ public class RuntimeHints {
|
||||
|
||||
private final ResourceHints resources = new ResourceHints();
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private final SerializationHints serialization = new SerializationHints();
|
||||
|
||||
private final ProxyHints proxies = new ProxyHints();
|
||||
@@ -63,7 +64,10 @@ public class RuntimeHints {
|
||||
/**
|
||||
* Provide access to serialization-based hints.
|
||||
* @return serialization hints
|
||||
* @deprecated in favor of {@link #reflection()}
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
@Deprecated(since = "7.0.6", forRemoval = true)
|
||||
public SerializationHints serialization() {
|
||||
return this.serialization;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,10 @@ import org.jspecify.annotations.Nullable;
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.0
|
||||
* @see Serializable
|
||||
* @deprecated in favor of {@link ReflectionHints}
|
||||
*/
|
||||
@Deprecated(since = "7.0.6", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public class SerializationHints {
|
||||
|
||||
private final Set<JavaSerializationHint> javaSerializationHints;
|
||||
|
||||
@@ -53,6 +53,8 @@ public final class TypeHint implements ConditionalHint {
|
||||
|
||||
private final Set<MemberCategory> memberCategories;
|
||||
|
||||
private final @Nullable Boolean serializable;
|
||||
|
||||
|
||||
private TypeHint(Builder builder) {
|
||||
this.type = builder.type;
|
||||
@@ -61,6 +63,7 @@ public final class TypeHint implements ConditionalHint {
|
||||
this.fields = builder.fields.stream().map(FieldHint::new).collect(Collectors.toSet());
|
||||
this.constructors = builder.constructors.values().stream().map(ExecutableHint.Builder::build).collect(Collectors.toSet());
|
||||
this.methods = builder.methods.values().stream().map(ExecutableHint.Builder::build).collect(Collectors.toSet());
|
||||
this.serializable = builder.serializable;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,6 +123,15 @@ public final class TypeHint implements ConditionalHint {
|
||||
return this.memberCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to register this type for Java serialization.
|
||||
* @return whether to register this type for Java serialization.
|
||||
* @since 7.0.6
|
||||
*/
|
||||
public @Nullable Boolean getSerializable() {
|
||||
return this.serializable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return TypeHint.class.getSimpleName() + "[type=" + this.type + "]";
|
||||
@@ -153,6 +165,8 @@ public final class TypeHint implements ConditionalHint {
|
||||
|
||||
private final Set<MemberCategory> memberCategories = new HashSet<>();
|
||||
|
||||
private @Nullable Boolean serializable;
|
||||
|
||||
Builder(TypeReference type) {
|
||||
this.type = type;
|
||||
}
|
||||
@@ -260,6 +274,17 @@ public final class TypeHint implements ConditionalHint {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify if this type should be registered for Java serialization.
|
||||
* @param serializable whether to register this type for Java serialization.
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 7.0.6
|
||||
*/
|
||||
public Builder withJavaSerialization(@Nullable Boolean serializable) {
|
||||
this.serializable = serializable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link TypeHint} based on the state of this builder.
|
||||
* @return a type hint
|
||||
|
||||
+47
@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -297,6 +298,30 @@ public class ReflectionHintsPredicates {
|
||||
return new FieldHintPredicate(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a predicate that checks whether Java serialization is configured according to the given flag.
|
||||
* @param type the type to check
|
||||
* @param serializable the expected serializable flag
|
||||
* @return the {@link RuntimeHints} predicate
|
||||
* @since 7.0.6
|
||||
*/
|
||||
public Predicate<RuntimeHints> onJavaSerialization(Class<?> type, @Nullable Boolean serializable) {
|
||||
Assert.notNull(type, "'type' must not be null");
|
||||
return new SerializationdHintPredicate(TypeReference.of(type), serializable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a predicate that checks whether Java serialization is configured according to the given flag.
|
||||
* @param typeReference the type reference to check
|
||||
* @param serializable the expected serializable flag
|
||||
* @return the {@link RuntimeHints} predicate
|
||||
* @since 7.0.6
|
||||
*/
|
||||
public Predicate<RuntimeHints> onJavaSerialization(TypeReference typeReference, @Nullable Boolean serializable) {
|
||||
Assert.notNull(typeReference, "'typeReference' must not be null");
|
||||
return new SerializationdHintPredicate(typeReference, serializable);
|
||||
}
|
||||
|
||||
|
||||
public static class TypeHintPredicate implements Predicate<RuntimeHints> {
|
||||
|
||||
@@ -509,4 +534,26 @@ public class ReflectionHintsPredicates {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SerializationdHintPredicate implements Predicate<RuntimeHints> {
|
||||
|
||||
private final TypeReference typeReference;
|
||||
|
||||
private final @Nullable Boolean serializable;
|
||||
|
||||
SerializationdHintPredicate(TypeReference typeReference, @Nullable Boolean serializable) {
|
||||
this.typeReference = typeReference;
|
||||
this.serializable = serializable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(RuntimeHints runtimeHints) {
|
||||
TypeHint typeHint = runtimeHints.reflection().getTypeHint(this.typeReference);
|
||||
if (typeHint == null) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(typeHint.getSerializable(), this.serializable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
@@ -46,6 +46,7 @@ public abstract class RuntimeHintsPredicates {
|
||||
|
||||
private static final ResourceHintsPredicates resource = new ResourceHintsPredicates();
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static final SerializationHintsPredicates serialization = new SerializationHintsPredicates();
|
||||
|
||||
private static final ProxyHintsPredicates proxies = new ProxyHintsPredicates();
|
||||
@@ -73,7 +74,10 @@ public abstract class RuntimeHintsPredicates {
|
||||
/**
|
||||
* Return a predicate generator for {@link SerializationHints serialization hints}.
|
||||
* @return the predicate generator
|
||||
* @deprecated in favor of {@link #reflection()}
|
||||
*/
|
||||
@Deprecated(since = "7.0.6", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public static SerializationHintsPredicates serialization() {
|
||||
return serialization;
|
||||
}
|
||||
|
||||
+3
@@ -29,7 +29,10 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.0
|
||||
* @deprecated in favor of {@link ReflectionHintsPredicates}
|
||||
*/
|
||||
@Deprecated(since = "7.0.6", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public class SerializationHintsPredicates {
|
||||
|
||||
SerializationHintsPredicates() {
|
||||
|
||||
+8
-3
@@ -44,12 +44,17 @@ public abstract class NativeConfigurationWriter {
|
||||
}
|
||||
|
||||
private boolean hasAnyHint(RuntimeHints hints) {
|
||||
return (hints.serialization().javaSerializationHints().findAny().isPresent() ||
|
||||
hints.proxies().jdkProxyHints().findAny().isPresent() ||
|
||||
return (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());
|
||||
hints.jni().typeHints().findAny().isPresent() ||
|
||||
hasAnyDeprecatedHint(hints));
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private boolean hasAnyDeprecatedHint(RuntimeHints hints) {
|
||||
return hints.serialization().javaSerializationHints().findAny().isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+35
-4
@@ -22,6 +22,7 @@ import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -32,6 +33,7 @@ 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.JavaSerializationHint;
|
||||
import org.springframework.aot.hint.JdkProxyHint;
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
@@ -62,16 +64,28 @@ class ReflectionHintsAttributes {
|
||||
};
|
||||
|
||||
public List<Map<String, Object>> reflection(RuntimeHints hints) {
|
||||
List<Map<String, Object>> reflectionHints = new ArrayList<>();
|
||||
reflectionHints.addAll(hints.reflection().typeHints()
|
||||
.sorted(Comparator.comparing(TypeHint::getType))
|
||||
.map(this::toAttributes).toList());
|
||||
List<Map<String, Object>> reflectionHints = new ArrayList<>(reflectionHints(hints));
|
||||
reflectionHints.addAll(hints.proxies().jdkProxyHints()
|
||||
.sorted(JDK_PROXY_HINT_COMPARATOR)
|
||||
.map(this::toAttributes).toList());
|
||||
return reflectionHints;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private List<Map<String, Object>> reflectionHints(RuntimeHints hints) {
|
||||
Map<TypeReference, Map<String, Object>> allTypeHints = hints.reflection().typeHints()
|
||||
.map(this::toAttributes).collect(Collectors.toMap((attributes -> (TypeReference) Objects.requireNonNull(attributes.get("type"))),
|
||||
attributes -> attributes));
|
||||
hints.serialization().javaSerializationHints().forEach(hint -> {
|
||||
allTypeHints.merge(hint.getType(), toAttributes(hint),
|
||||
(currentAttributes, newAttributes) -> {
|
||||
handleSerializable(currentAttributes, true);
|
||||
return currentAttributes;
|
||||
});
|
||||
});
|
||||
return allTypeHints.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).map(Map.Entry::getValue).toList();
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> jni(RuntimeHints hints) {
|
||||
List<Map<String, Object>> jniHints = new ArrayList<>();
|
||||
jniHints.addAll(hints.jni().typeHints()
|
||||
@@ -88,6 +102,16 @@ class ReflectionHintsAttributes {
|
||||
handleFields(attributes, hint.fields());
|
||||
handleExecutables(attributes, Stream.concat(
|
||||
hint.constructors(), hint.methods()).sorted().toList());
|
||||
handleSerializable(attributes, hint.getSerializable());
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private Map<String, Object> toAttributes(JavaSerializationHint serializationHint) {
|
||||
LinkedHashMap<String, Object> attributes = new LinkedHashMap<>();
|
||||
handleCondition(attributes, serializationHint);
|
||||
attributes.put("type", serializationHint.getType());
|
||||
handleSerializable(attributes, true);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@@ -148,7 +172,14 @@ class ReflectionHintsAttributes {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
handleCondition(attributes, hint);
|
||||
attributes.put("type", Map.of("proxy", hint.getProxiedInterfaces()));
|
||||
handleSerializable(attributes, hint.getSerializable());
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private void handleSerializable(Map<String, Object> attributes, @Nullable Boolean serializable) {
|
||||
if (serializable != null) {
|
||||
attributes.put("serializable", serializable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-10
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.aot.nativex;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -35,8 +36,9 @@ import org.springframework.aot.hint.ResourcePatternHints;
|
||||
* @author Stephane Nicoll
|
||||
* @author Brian Clozel
|
||||
* @since 6.0
|
||||
* @see <a href="https://www.graalvm.org/22.1/reference-manual/native-image/Resources/">Accessing Resources in Native Images</a>
|
||||
* @see <a href="https://www.graalvm.org/22.1/reference-manual/native-image/BuildConfiguration/">Native Image Build Configuration</a>
|
||||
* @see <a href="https://www.graalvm.org/jdk25/reference-manual/native-image/metadata/#resources">Accessing Resources in Native Images</a>
|
||||
* @see <a href="https://www.graalvm.org/jdk25/reference-manual/native-image/metadata/#resource-bundles">Accessing Resource Bundles in Native Images</a>
|
||||
* @see <a href="https://www.graalvm.org/jdk25/reference-manual/native-image/overview/BuildConfiguration">Native Image Build Configuration</a>
|
||||
*/
|
||||
class ResourceHintsAttributes {
|
||||
|
||||
@@ -48,22 +50,21 @@ class ResourceHintsAttributes {
|
||||
|
||||
|
||||
public List<Map<String, Object>> resources(ResourceHints hint) {
|
||||
return hint.resourcePatternHints()
|
||||
List<Map<String, Object>> resourceHints = new ArrayList<>();
|
||||
resourceHints.addAll(hint.resourcePatternHints()
|
||||
.map(ResourcePatternHints::getIncludes).flatMap(List::stream).distinct()
|
||||
.sorted(RESOURCE_PATTERN_HINT_COMPARATOR)
|
||||
.map(this::toAttributes).toList();
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> resourceBundles(ResourceHints hint) {
|
||||
return hint.resourceBundleHints()
|
||||
.map(this::toAttributes).toList());
|
||||
resourceHints.addAll(hint.resourceBundleHints()
|
||||
.sorted(RESOURCE_BUNDLE_HINT_COMPARATOR)
|
||||
.map(this::toAttributes).toList();
|
||||
.map(this::toAttributes).toList());
|
||||
return resourceHints;
|
||||
}
|
||||
|
||||
private Map<String, Object> toAttributes(ResourceBundleHint hint) {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
handleCondition(attributes, hint);
|
||||
attributes.put("name", hint.getBaseName());
|
||||
attributes.put("bundle", hint.getBaseName());
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,9 @@ import org.springframework.core.SpringVersion;
|
||||
* GraalVM {@code native-image} compiler, typically named {@code reachability-metadata.json}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Stephane Nicoll
|
||||
* @since 7.0
|
||||
* @see <a href="https://www.graalvm.org/jdk23/reference-manual/native-image/metadata/#specifying-metadata-with-json">GraalVM Reachability Metadata</a>
|
||||
* @see <a href="https://www.graalvm.org/jdk25/reference-manual/native-image/metadata">GraalVM Reachability Metadata</a>
|
||||
*/
|
||||
class RuntimeHintsWriter {
|
||||
|
||||
@@ -51,14 +52,6 @@ class RuntimeHintsWriter {
|
||||
if (!resourceHints.isEmpty()) {
|
||||
document.put("resources", resourceHints);
|
||||
}
|
||||
List<Map<String, Object>> resourceBundles = new ResourceHintsAttributes().resourceBundles(hints.resources());
|
||||
if (!resourceBundles.isEmpty()) {
|
||||
document.put("bundles", resourceBundles);
|
||||
}
|
||||
List<Map<String, Object>> serialization = new SerializationHintsAttributes().toAttributes(hints.serialization());
|
||||
if (!serialization.isEmpty()) {
|
||||
document.put("serialization", serialization);
|
||||
}
|
||||
|
||||
writer.writeObject(document);
|
||||
}
|
||||
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-present 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.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aot.hint.ConditionalHint;
|
||||
import org.springframework.aot.hint.JavaSerializationHint;
|
||||
import org.springframework.aot.hint.SerializationHints;
|
||||
|
||||
/**
|
||||
* Collect {@link SerializationHints} as map attributes ready for JSON serialization for the GraalVM
|
||||
* {@code native-image} compiler.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Stephane Nicoll
|
||||
* @author Brian Clozel
|
||||
* @see <a href="https://www.graalvm.org/jdk23/reference-manual/native-image/overview/BuildConfiguration/">Native Image Build Configuration</a>
|
||||
*/
|
||||
class SerializationHintsAttributes {
|
||||
|
||||
private static final Comparator<JavaSerializationHint> JAVA_SERIALIZATION_HINT_COMPARATOR =
|
||||
Comparator.comparing(JavaSerializationHint::getType);
|
||||
|
||||
public List<Map<String, Object>> toAttributes(SerializationHints hints) {
|
||||
return hints.javaSerializationHints()
|
||||
.sorted(JAVA_SERIALIZATION_HINT_COMPARATOR)
|
||||
.map(this::toAttributes).toList();
|
||||
}
|
||||
|
||||
private Map<String, Object> toAttributes(JavaSerializationHint serializationHint) {
|
||||
LinkedHashMap<String, Object> attributes = new LinkedHashMap<>();
|
||||
handleCondition(attributes, serializationHint);
|
||||
attributes.put("type", serializationHint.getType());
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private void handleCondition(Map<String, Object> attributes, ConditionalHint hint) {
|
||||
if (hint.getReachableType() != null) {
|
||||
Map<String, Object> conditionAttributes = new LinkedHashMap<>();
|
||||
conditionAttributes.put("typeReached", hint.getReachableType());
|
||||
attributes.put("condition", conditionAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -25,5 +25,7 @@ import java.io.Serializable
|
||||
* @author Sebastien Deleuze
|
||||
* @since 6.0.5
|
||||
*/
|
||||
@Suppress("removal", "DEPRECATION")
|
||||
@Deprecated(level = DeprecationLevel.WARNING, message = "Use ReflectionHints")
|
||||
inline fun <reified T : Serializable> SerializationHints.registerType(noinline serializationHint: (JavaSerializationHint.Builder) -> Unit = {}) =
|
||||
registerType(T::class.java, serializationHint::invoke)
|
||||
|
||||
@@ -80,6 +80,18 @@ class ProxyHintsTests {
|
||||
assertThat(this.proxyHints.jdkProxyHints()).singleElement().satisfies(proxiedInterfaces(Function.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerJdkProxyWithJavaSerialization() {
|
||||
this.proxyHints.registerJdkProxy(hint -> {
|
||||
hint.proxiedInterfaces(TypeReference.of("com.example.Test"));
|
||||
hint.javaSerialization(true);
|
||||
});
|
||||
assertThat(this.proxyHints.jdkProxyHints()).singleElement().satisfies(hint -> {
|
||||
assertThat(hint.getProxiedInterfaces()).containsExactly(TypeReference.of("com.example.Test"));
|
||||
assertThat(hint.getSerializable()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static Consumer<JdkProxyHint.Builder> springProxy(String proxiedInterface) {
|
||||
return builder -> builder.proxiedInterfaces(toTypeReferences(
|
||||
|
||||
@@ -53,6 +53,8 @@ class RuntimeHintsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Deprecated
|
||||
@SuppressWarnings("removal")
|
||||
void javaSerializationHintWithClass() {
|
||||
this.hints.serialization().registerType(String.class);
|
||||
assertThat(this.hints.serialization().javaSerializationHints().map(JavaSerializationHint::getType))
|
||||
|
||||
@@ -27,6 +27,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("removal")
|
||||
class SerializationHintsTests {
|
||||
|
||||
private final SerializationHints serializationHints = new SerializationHints();
|
||||
|
||||
+30
@@ -435,6 +435,36 @@ class ReflectionHintsPredicatesTests {
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class JavaSerialization {
|
||||
|
||||
@Test
|
||||
void javaSerializationMatchesRegisteredClass() {
|
||||
runtimeHints.reflection().registerJavaSerialization(SampleClass.class);
|
||||
assertPredicateMatches(reflection.onJavaSerialization(SampleClass.class, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaSerializationMatchesRegisteredTypeReference() {
|
||||
runtimeHints.reflection().registerType(TypeReference.of(SampleClass.class),
|
||||
type -> type.withJavaSerialization(false));
|
||||
assertPredicateMatches(reflection.onJavaSerialization(TypeReference.of(SampleClass.class), false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaSerializationDoesNotMatchOnMissingType() {
|
||||
runtimeHints.reflection().registerJavaSerialization(SampleClass.class);
|
||||
assertPredicateDoesNotMatch(reflection.onJavaSerialization(Integer.class, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaSerializationDoesNotMatchOnInvalidSerializationFlag() {
|
||||
runtimeHints.reflection().registerJavaSerialization(SampleClass.class);
|
||||
assertPredicateDoesNotMatch(reflection.onJavaSerialization(SampleClass.class, false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void assertPredicateMatches(Predicate<RuntimeHints> predicate) {
|
||||
assertThat(predicate).accepts(this.runtimeHints);
|
||||
}
|
||||
|
||||
+2
@@ -28,6 +28,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("removal")
|
||||
class SerializationHintsPredicatesTests {
|
||||
|
||||
private final SerializationHintsPredicates serialization = new SerializationHintsPredicates();
|
||||
|
||||
+7
-7
@@ -35,7 +35,6 @@ 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;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.core.codec.StringDecoder;
|
||||
|
||||
@@ -47,6 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Sebastien Deleuze
|
||||
* @author Janne Valkealahti
|
||||
* @author Sam Brannen
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class FileNativeConfigurationWriterTests {
|
||||
|
||||
@@ -66,15 +66,15 @@ class FileNativeConfigurationWriterTests {
|
||||
void serializationConfig() throws IOException, JSONException {
|
||||
FileNativeConfigurationWriter generator = new FileNativeConfigurationWriter(tempDir);
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
SerializationHints serializationHints = hints.serialization();
|
||||
serializationHints.registerType(Integer.class);
|
||||
serializationHints.registerType(Long.class);
|
||||
ReflectionHints reflectionHints = hints.reflection();
|
||||
reflectionHints.registerJavaSerialization(Integer.class);
|
||||
reflectionHints.registerJavaSerialization(Long.class);
|
||||
generator.write(hints);
|
||||
assertEquals("""
|
||||
{
|
||||
"serialization": [
|
||||
{ "type": "java.lang.Integer" },
|
||||
{ "type": "java.lang.Long" }
|
||||
"reflection": [
|
||||
{ "type": "java.lang.Integer", "serializable": true },
|
||||
{ "type": "java.lang.Long", "serializable": true }
|
||||
]
|
||||
}
|
||||
""");
|
||||
|
||||
+55
-13
@@ -65,7 +65,7 @@ class RuntimeHintsWriterTests {
|
||||
builder.schemaMappers(schemaMappers -> schemaMappers.mapPrefix("https://www.graalvm.org/", "classpath:org/springframework/aot/nativex/"))
|
||||
);
|
||||
SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build();
|
||||
JSON_SCHEMA = jsonSchemaFactory.getSchema(SchemaLocation.of("https://www.graalvm.org/reachability-metadata-schema-v1.0.0.json"), config);
|
||||
JSON_SCHEMA = jsonSchemaFactory.getSchema(SchemaLocation.of("https://www.graalvm.org/reachability-metadata-schema-v1.2.0.json"), config);
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -89,7 +89,8 @@ class RuntimeHintsWriterTests {
|
||||
.withField("DEFAULT_CHARSET")
|
||||
.withField("defaultCharset")
|
||||
.withField("aScore")
|
||||
.withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)), ExecutableMode.INVOKE));
|
||||
.withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)), ExecutableMode.INVOKE)
|
||||
.withJavaSerialization(true));
|
||||
assertEquals("""
|
||||
{
|
||||
"reflection": [
|
||||
@@ -110,7 +111,8 @@ class RuntimeHintsWriterTests {
|
||||
],
|
||||
"methods": [
|
||||
{ "name": "setDefaultCharset", "parameterTypes": [ "java.nio.charset.Charset" ] }
|
||||
]
|
||||
],
|
||||
"serializable": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -204,6 +206,23 @@ class RuntimeHintsWriterTests {
|
||||
""", hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void serializationEnabled() throws JSONException {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
hints.reflection().registerType(Integer.class, builder -> builder.withJavaSerialization(true));
|
||||
|
||||
assertEquals("""
|
||||
{
|
||||
"reflection": [
|
||||
{
|
||||
"type": "java.lang.Integer",
|
||||
"serializable": true
|
||||
}
|
||||
]
|
||||
}
|
||||
""", hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignoreLambda() throws JSONException {
|
||||
Runnable anonymousRunnable = () -> {};
|
||||
@@ -409,15 +428,17 @@ class RuntimeHintsWriterTests {
|
||||
hints.resources().registerResourceBundle("com.example.message");
|
||||
assertEquals("""
|
||||
{
|
||||
"bundles": [
|
||||
{ "name": "com.example.message"},
|
||||
{ "name": "com.example.message2"}
|
||||
"resources": [
|
||||
{ "bundle": "com.example.message"},
|
||||
{ "bundle": "com.example.message2"}
|
||||
]
|
||||
}""", hints);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@Deprecated(forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
class SerializationHintsTests {
|
||||
|
||||
@Test
|
||||
@@ -432,8 +453,8 @@ class RuntimeHintsWriterTests {
|
||||
hints.serialization().registerType(TypeReference.of(String.class));
|
||||
assertEquals("""
|
||||
{
|
||||
"serialization": [
|
||||
{ "type": "java.lang.String" }
|
||||
"reflection": [
|
||||
{ "type": "java.lang.String", "serializable": true }
|
||||
]
|
||||
}
|
||||
""", hints);
|
||||
@@ -447,9 +468,9 @@ class RuntimeHintsWriterTests {
|
||||
.registerType(TypeReference.of(String.class));
|
||||
assertEquals("""
|
||||
{
|
||||
"serialization": [
|
||||
{ "type": "java.lang.String" },
|
||||
{ "type": "org.springframework.core.env.Environment" }
|
||||
"reflection": [
|
||||
{ "type": "java.lang.String", "serializable": true },
|
||||
{ "type": "org.springframework.core.env.Environment", "serializable": true }
|
||||
]
|
||||
}
|
||||
""", hints);
|
||||
@@ -462,8 +483,8 @@ class RuntimeHintsWriterTests {
|
||||
builder -> builder.onReachableType(TypeReference.of("org.example.Test")));
|
||||
assertEquals("""
|
||||
{
|
||||
"serialization": [
|
||||
{ "condition": { "typeReached": "org.example.Test" }, "type": "java.lang.String" }
|
||||
"reflection": [
|
||||
{ "condition": { "typeReached": "org.example.Test" }, "type": "java.lang.String", "serializable": true }
|
||||
]
|
||||
}
|
||||
""", hints);
|
||||
@@ -567,6 +588,27 @@ class RuntimeHintsWriterTests {
|
||||
""", hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWriteSerialization() throws JSONException {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
hints.proxies().registerJdkProxy(hint -> {
|
||||
hint.proxiedInterfaces(Function.class);
|
||||
hint.javaSerialization(true);
|
||||
});
|
||||
assertEquals("""
|
||||
{
|
||||
"reflection": [
|
||||
{
|
||||
"type": {
|
||||
"proxy": ["java.util.function.Function"]
|
||||
},
|
||||
"serializable": true
|
||||
}
|
||||
]
|
||||
}
|
||||
""", hints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void assertEquals(String expectedString, RuntimeHints hints) throws JSONException {
|
||||
|
||||
+1
@@ -27,6 +27,7 @@ import java.util.function.Consumer
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
@Suppress("REMOVAL", "DEPRECATION")
|
||||
class SerializationHintsExtensionsTests {
|
||||
|
||||
private val serializationHints = mockk<SerializationHints>()
|
||||
|
||||
-362
@@ -1,362 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
||||
"$id": "https://www.graalvm.org/reachability-metadata-schema-v1.0.0.json",
|
||||
"title": "JSON schema for the reachability metadata used by GraalVM Native Image",
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"properties": {
|
||||
"comment": {
|
||||
"title": "A comment applying to the whole file (e.g., generation date, author, etc.)",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default": ""
|
||||
},
|
||||
"reflection": {
|
||||
"title": "Metadata to ensure elements are reachable through reflection",
|
||||
"$ref": "#/$defs/reflection"
|
||||
},
|
||||
"jni": {
|
||||
"title": "Metadata to ensure elements are reachable through JNI",
|
||||
"$ref": "#/$defs/reflection"
|
||||
},
|
||||
"serialization": {
|
||||
"title": "Metadata for types that are serialized or deserialized at run time. The types must extend 'java.io.Serializable'.",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Enables serializing and deserializing objects of the class specified by <type>",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"title": "Reason for the type's inclusion in the serialization metadata",
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"title": "Condition under which the class should be registered for serialization",
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"type": {
|
||||
"title": "Type descriptor of the class that should be registered for serialization",
|
||||
"$ref": "#/$defs/type"
|
||||
},
|
||||
"customTargetConstructorClass": {
|
||||
"title": "Fully qualified name of the class whose constructor should be used to serialize the class specified by <type>",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"title": "Metadata to ensure resources are available",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Resource that should be available",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"title": "Reason for the resource's inclusion in the metadata",
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"title": "Condition under which the resource should be registered for runtime access",
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"module": {
|
||||
"title": "Module containing the resource",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"glob": {
|
||||
"title": "Resource name or pattern matching multiple resources (accepts * and ** wildcards)",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"glob"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"bundles": {
|
||||
"title": "Metadata to ensure resource bundles are available",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Resource bundle that should be available",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"title": "Reason for the resource bundle's inclusion in the metadata",
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"title": "Condition under which the resource bundle should be registered for runtime access",
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"name": {
|
||||
"title": "Name of the resource bundle",
|
||||
"type": "string"
|
||||
},
|
||||
"locales": {
|
||||
"title": "List of locales that should be registered for this resource bundle",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
"additionalProperties": false,
|
||||
|
||||
"$defs": {
|
||||
"reflection": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Elements that should be registered for reflection for a specified type",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"title": "Reason for the element's inclusion",
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"title": "Condition under which the class should be registered for reflection",
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"type": {
|
||||
"title": "Type descriptor of the class that should be registered for reflection",
|
||||
"$ref": "#/$defs/type"
|
||||
},
|
||||
"methods": {
|
||||
"title": "List of methods that should be registered for the type declared in <type>",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Method descriptor of the method that should be registered for reflection",
|
||||
"$ref": "#/$defs/method"
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"title": "List of class fields that can be read or written to for the type declared in <type>",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Field descriptor of the field that should be registered for reflection",
|
||||
"$ref": "#/$defs/field"
|
||||
}
|
||||
},
|
||||
"allDeclaredMethods": {
|
||||
"title": "Register all declared methods from the type for reflective invocation",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allDeclaredFields": {
|
||||
"title": "Register all declared fields from the type for reflective access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allDeclaredConstructors": {
|
||||
"title": "Register all declared constructors from the type for reflective invocation",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allPublicMethods": {
|
||||
"title": "Register all public methods from the type for reflective invocation",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allPublicFields": {
|
||||
"title": "Register all public fields from the type for reflective access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allPublicConstructors": {
|
||||
"title": "Register all public constructors from the type for reflective invocation",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"unsafeAllocated": {
|
||||
"title": "Allow objects of this class to be instantiated with a call to jdk.internal.misc.Unsafe#allocateInstance or JNI's AllocObject",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"jni": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Elements that should be registered for JNI for a specified type",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"title": "Reason for the element's inclusion",
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"title": "Condition under which the class should be registered for JNI",
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"type": {
|
||||
"title": "Type descriptor of the class that should be registered for JNI",
|
||||
"$ref": "#/$defs/type"
|
||||
},
|
||||
"methods": {
|
||||
"title": "List of methods that should be registered for the type declared in <type>",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Method descriptor of the method that should be registered for JNI",
|
||||
"$ref": "#/$defs/method"
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"title": "List of class fields that can be read or written to for the type declared in <type>",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Field descriptor of the field that should be registered for JNI",
|
||||
"$ref": "#/$defs/field"
|
||||
}
|
||||
},
|
||||
"allDeclaredMethods": {
|
||||
"title": "Register all declared methods from the type for JNI access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allDeclaredFields": {
|
||||
"title": "Register all declared fields from the type for JNI access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allDeclaredConstructors": {
|
||||
"title": "Register all declared constructors from the type for JNI access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allPublicMethods": {
|
||||
"title": "Register all public methods from the type for JNI access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allPublicFields": {
|
||||
"title": "Register all public fields from the type for JNI access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allPublicConstructors": {
|
||||
"title": "Register all public constructors from the type for JNI access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"default": []
|
||||
},
|
||||
"condition": {
|
||||
"title": "Condition used by GraalVM Native Image metadata files",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"typeReached": {
|
||||
"title": "Type descriptor of a class that must be reached in order to enable the corresponding registration",
|
||||
"$ref": "#/$defs/type"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"typeReached"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"type": {
|
||||
"title": "Type descriptors used by GraalVM Native Image metadata files",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"proxy": {
|
||||
"title": "List of interfaces defining the proxy class",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Fully qualified name of the interface defining the proxy class",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"proxy"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": {
|
||||
"title": "Method descriptors used by GraalVM Native Image metadata files",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"title": "Method name that should be registered for this class",
|
||||
"type": "string"
|
||||
},
|
||||
"parameterTypes": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "List of the method's parameter types",
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"field": {
|
||||
"title": "Field descriptors used by GraalVM Native Image metadata files",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"title": "Name of the field that should be registered for reflection",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
+469
@@ -0,0 +1,469 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
||||
"$id": "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reachability-metadata-schema-v1.2.0.json",
|
||||
"title": "JSON schema for the reachability metadata used by GraalVM Native Image",
|
||||
"version": "1.2.0",
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"properties": {
|
||||
"comment": {
|
||||
"title": "Comment(s) applying to the whole file (e.g., generation date, author, etc.)",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default": ""
|
||||
},
|
||||
"reflection": {
|
||||
"title": "Metadata to ensure elements are accessible via reflection",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Elements that should be registered for reflection for a specified type",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"reason": {
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"type": {
|
||||
"title": "Type descriptor of the class that should be registered for reflection",
|
||||
"$ref": "#/$defs/type"
|
||||
},
|
||||
"methods": {
|
||||
"title": "List of methods that should be registered for the type declared in <type>",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Method descriptor of the method that should be registered for reflection",
|
||||
"$ref": "#/$defs/method"
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"title": "List of class fields that can be read or written to for the type declared in <type>",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"title": "Field descriptor of the field that should be registered for reflection",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"title": "Name of the field that should be registered for reflection",
|
||||
"type": "string",
|
||||
"pattern": "^[^.;\\[/]+$"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"allDeclaredMethods": {
|
||||
"title": "Register all declared methods from the type for reflective invocation",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allDeclaredFields": {
|
||||
"title": "Register all declared fields from the type for reflective access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allDeclaredConstructors": {
|
||||
"title": "Register all declared constructors from the type for reflective invocation",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allPublicMethods": {
|
||||
"title": "Register all public methods from the type for reflective invocation",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allPublicFields": {
|
||||
"title": "Register all public fields from the type for reflective access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allPublicConstructors": {
|
||||
"title": "Register all public constructors from the type for reflective invocation",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"unsafeAllocated": {
|
||||
"title": "Allow objects of this class to be instantiated with a call to jdk.internal.misc.Unsafe#allocateInstance or JNI's AllocObject",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"serializable": {
|
||||
"title": "Allow objects of this class to be serialized and deserialized",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"jniAccessible": {
|
||||
"title": "Register the type, including all registered fields and methods, for runtime JNI access",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"title": "Metadata to ensure resources are accessible",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"title": "Resource that should be accessible",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"module": {
|
||||
"title": "Module containing the resource",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"glob": {
|
||||
"title": "Resource name or pattern matching multiple resources (accepts * and ** wildcards)",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"glob"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"title": "Resource bundle that should be available",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"module": {
|
||||
"title": "Module containing the resource bundle",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"bundle": {
|
||||
"title": "Resource bundle name",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"bundle"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"foreign": {
|
||||
"properties": {
|
||||
"downcalls": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"properties": {
|
||||
"reason": {
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"returnType": {
|
||||
"type": "string",
|
||||
"title": "Memory layout definition (allows canonical layouts; see `java.lang.foreign.Linker`)"
|
||||
},
|
||||
"parameterTypes": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string",
|
||||
"title": "Memory layout definition (allows canonical layouts; see `java.lang.foreign.Linker`)"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "List of the function descriptor's parameter types"
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"title": "Linker options (see `java.lang.foreign.Linker.Option`)",
|
||||
"properties": {
|
||||
"captureCallState": {
|
||||
"type": "boolean",
|
||||
"title": "Specifies whether a call state should be captured. The specific states to capture are determined at run time. See also: `java.lang.foreign.Linker.Option.captureCallState`"
|
||||
},
|
||||
"critical": {
|
||||
"type": "object",
|
||||
"title": "See `java.lang.foreign.Linker.Option.critical`",
|
||||
"properties": {
|
||||
"allowHeapAccess": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"firstVariadicArg": {
|
||||
"type": "integer",
|
||||
"title": "See `java.lang.foreign.Linker.Option.firstVariadicArg`"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"returnType",
|
||||
"parameterTypes"
|
||||
],
|
||||
"type": "object",
|
||||
"title": "Function descriptor to be registered for a downcall"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "List of function descriptors that should be registered for downcalls"
|
||||
},
|
||||
"upcalls": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"properties": {
|
||||
"reason": {
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"returnType": {
|
||||
"type": "string",
|
||||
"title": "Memory layout definition (allows canonical layouts; see `java.lang.foreign.Linker`)"
|
||||
},
|
||||
"parameterTypes": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string",
|
||||
"title": "Memory layout definition (allows canonical layouts; see `java.lang.foreign.Linker`)"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "List of the function descriptor's parameter types"
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"title": "Linker options (see `java.lang.foreign.Linker.Option`)",
|
||||
"description": "Currently, no linker options are allowed for upcalls. This may change in the future.",
|
||||
"properties": {},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"returnType",
|
||||
"parameterTypes"
|
||||
],
|
||||
"type": "object",
|
||||
"title": "Function descriptor to be registered for an upcall"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "List of function descriptors that should be registered for upcalls"
|
||||
},
|
||||
"directUpcalls": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"properties": {
|
||||
"reason": {
|
||||
"$ref": "#/$defs/reason"
|
||||
},
|
||||
"condition": {
|
||||
"$ref": "#/$defs/condition"
|
||||
},
|
||||
"class": {
|
||||
"$ref": "#/$defs/className",
|
||||
"title": "Fully-qualified class name (e.g., `org.package.OuterClass$InnerClass`)"
|
||||
},
|
||||
"method": {
|
||||
"type": "string",
|
||||
"title": "Method name"
|
||||
},
|
||||
"returnType": {
|
||||
"type": "string",
|
||||
"title": "Memory layout definition (allows canonical layouts; see `java.lang.foreign.Linker`)"
|
||||
},
|
||||
"parameterTypes": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string",
|
||||
"title": "Memory layout definition (allows canonical layouts; see `java.lang.foreign.Linker`)"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "List of the function descriptor's parameter types"
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"title": "Linker options (see `java.lang.foreign.Linker.Option`)",
|
||||
"description": "Currently, no linker options are allowed for direct upcalls. This may change in the future.",
|
||||
"properties": {},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"class",
|
||||
"method"
|
||||
],
|
||||
"type": "object",
|
||||
"title": "Java method and function descriptor to be registered for a direct upcall"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "List of Java methods and function descriptors that should be registered for direct upcalls"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"title": "JSON schema for the FFM API configuration used by GraalVM Native Image",
|
||||
"description": "For a description and examples of writing an FFM API configuration, see: https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/FFM-API.md"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
"additionalProperties": false,
|
||||
"$defs": {
|
||||
"className": {
|
||||
"type": "string",
|
||||
"pattern": "^[^.;\\[/]+(\\.[^.;\\[/]+)*$"
|
||||
},
|
||||
"typeName": {
|
||||
"type": "string",
|
||||
"pattern": "^[^.;\\[/]+(\\.[^.;\\[/]+)*(\\[])*$"
|
||||
},
|
||||
"reason": {
|
||||
"title": "Reason(s) for including this element (e.g., needed for establishing connections, or needed by method X#Y for task Z)",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default": ""
|
||||
},
|
||||
"condition": {
|
||||
"title": "Condition used to determine if the element will be accessible at run time",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"typeReached": {
|
||||
"title": "Type descriptor of a class that must be reached in order to allow access to the element",
|
||||
"$ref": "#/$defs/type"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"typeReached"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"type": {
|
||||
"title": "Type descriptors used by GraalVM Native Image metadata files",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/typeName"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"proxy": {
|
||||
"title": "A list of interfaces defining the proxy class",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"title": "Fully-qualified name of the interface defining the proxy class",
|
||||
"$ref": "#/$defs/className"
|
||||
}
|
||||
},
|
||||
"lambda": {
|
||||
"title": "Lambda class descriptor",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"declaringClass": {
|
||||
"title": "The class in which the lambda class is defined",
|
||||
"$ref": "#/$defs/className"
|
||||
},
|
||||
"declaringMethod": {
|
||||
"title": "The method in which the lambda class is defined",
|
||||
"$ref": "#/$defs/method"
|
||||
},
|
||||
"interfaces": {
|
||||
"title": "Non-empty list of interfaces implemented by the lambda class",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"title": "Fully-qualified name of the interface implemented by the lambda class",
|
||||
"$ref": "#/$defs/className"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"declaringClass",
|
||||
"interfaces"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"oneOf": [
|
||||
{
|
||||
"required": [
|
||||
"proxy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"lambda"
|
||||
]
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": {
|
||||
"title": "Method descriptors used by GraalVM Native Image metadata files",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"title": "Method name that should be registered for this class",
|
||||
"type": "string",
|
||||
"pattern": "^[^.;\\[/]+$"
|
||||
},
|
||||
"parameterTypes": {
|
||||
"items": {
|
||||
"title": "List of the method's parameter types",
|
||||
"$ref": "#/$defs/typeName"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"parameterTypes"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user