Write runtime hints with deterministic order
This commit updates the JSON writers to use a deterministic order for arrays. Previously, the order could change with the same content, breaking caching. Closes gh-31852
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.aot.nativex;
|
||||
import java.io.StringWriter;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -32,8 +33,9 @@ import org.springframework.aot.hint.TypeReference;
|
||||
* Tests for {@link ProxyHintsWriter}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ProxyHintsWriterTests {
|
||||
class ProxyHintsWriterTests {
|
||||
|
||||
@Test
|
||||
void empty() throws JSONException {
|
||||
@@ -63,6 +65,18 @@ public class ProxyHintsWriterTests {
|
||||
]""", hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWriteEntriesInNaturalOrder() throws JSONException {
|
||||
ProxyHints hints = new ProxyHints();
|
||||
hints.registerJdkProxy(Supplier.class);
|
||||
hints.registerJdkProxy(Function.class);
|
||||
assertEquals("""
|
||||
[
|
||||
{ "interfaces": [ "java.util.function.Function" ] },
|
||||
{ "interfaces": [ "java.util.function.Supplier" ] }
|
||||
]""", hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWriteInnerClass() throws JSONException {
|
||||
ProxyHints hints = new ProxyHints();
|
||||
@@ -88,7 +102,7 @@ public class ProxyHintsWriterTests {
|
||||
StringWriter out = new StringWriter();
|
||||
BasicJsonWriter writer = new BasicJsonWriter(out, "\t");
|
||||
ProxyHintsWriter.INSTANCE.write(writer, hints);
|
||||
JSONAssert.assertEquals(expectedString, out.toString(), JSONCompareMode.NON_EXTENSIBLE);
|
||||
JSONAssert.assertEquals(expectedString, out.toString(), JSONCompareMode.STRICT);
|
||||
}
|
||||
|
||||
interface Inner {
|
||||
|
||||
@@ -33,10 +33,13 @@ import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.core.codec.StringDecoder;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ReflectionHintsWriter}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ReflectionHintsWriterTests {
|
||||
|
||||
@@ -59,6 +62,7 @@ public class ReflectionHintsWriterTests {
|
||||
MemberCategory.PUBLIC_CLASSES, MemberCategory.DECLARED_CLASSES)
|
||||
.withField("DEFAULT_CHARSET")
|
||||
.withField("defaultCharset")
|
||||
.withField("aScore")
|
||||
.withConstructor(TypeReference.listOf(List.class, boolean.class, MimeType.class), ExecutableMode.INTROSPECT)
|
||||
.withMethod("setDefaultCharset", List.of(TypeReference.of(Charset.class)), ExecutableMode.INVOKE)
|
||||
.withMethod("getDefaultCharset", Collections.emptyList(), ExecutableMode.INTROSPECT));
|
||||
@@ -80,6 +84,7 @@ public class ReflectionHintsWriterTests {
|
||||
"allPublicClasses": true,
|
||||
"allDeclaredClasses": true,
|
||||
"fields": [
|
||||
{ "name": "aScore" },
|
||||
{ "name": "DEFAULT_CHARSET" },
|
||||
{ "name": "defaultCharset" }
|
||||
],
|
||||
@@ -203,17 +208,83 @@ public class ReflectionHintsWriterTests {
|
||||
|
||||
@Test
|
||||
void ignoreLambda() throws JSONException {
|
||||
Runnable anonymousRunnable = () -> { };
|
||||
Runnable anonymousRunnable = () -> {};
|
||||
ReflectionHints hints = new ReflectionHints();
|
||||
hints.registerType(anonymousRunnable.getClass());
|
||||
assertEquals("[]", hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortTypeHints() {
|
||||
ReflectionHints hints = new ReflectionHints();
|
||||
hints.registerType(Integer.class, builder -> {});
|
||||
hints.registerType(Long.class, builder -> {});
|
||||
|
||||
ReflectionHints hints2 = new ReflectionHints();
|
||||
hints2.registerType(Long.class, builder -> {});
|
||||
hints2.registerType(Integer.class, builder -> {});
|
||||
|
||||
assertThat(writeJson(hints)).isEqualTo(writeJson(hints2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortFieldHints() {
|
||||
ReflectionHints hints = new ReflectionHints();
|
||||
hints.registerType(Integer.class, builder -> {
|
||||
builder.withField("first");
|
||||
builder.withField("second");
|
||||
});
|
||||
ReflectionHints hints2 = new ReflectionHints();
|
||||
hints2.registerType(Integer.class, builder -> {
|
||||
builder.withField("second");
|
||||
builder.withField("first");
|
||||
});
|
||||
assertThat(writeJson(hints)).isEqualTo(writeJson(hints2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortConstructorHints() {
|
||||
ReflectionHints hints = new ReflectionHints();
|
||||
hints.registerType(Integer.class, builder -> {
|
||||
builder.withConstructor(List.of(TypeReference.of(String.class)), ExecutableMode.INVOKE);
|
||||
builder.withConstructor(List.of(TypeReference.of(String.class),
|
||||
TypeReference.of(Integer.class)), ExecutableMode.INVOKE);
|
||||
});
|
||||
|
||||
ReflectionHints hints2 = new ReflectionHints();
|
||||
hints2.registerType(Integer.class, builder -> {
|
||||
builder.withConstructor(List.of(TypeReference.of(String.class),
|
||||
TypeReference.of(Integer.class)), ExecutableMode.INVOKE);
|
||||
builder.withConstructor(List.of(TypeReference.of(String.class)), ExecutableMode.INVOKE);
|
||||
});
|
||||
assertThat(writeJson(hints)).isEqualTo(writeJson(hints2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortMethodHints() {
|
||||
ReflectionHints hints = new ReflectionHints();
|
||||
hints.registerType(Integer.class, builder -> {
|
||||
builder.withMethod("test", Collections.emptyList(), ExecutableMode.INVOKE);
|
||||
builder.withMethod("another", Collections.emptyList(), ExecutableMode.INVOKE);
|
||||
});
|
||||
|
||||
ReflectionHints hints2 = new ReflectionHints();
|
||||
hints2.registerType(Integer.class, builder -> {
|
||||
builder.withMethod("another", Collections.emptyList(), ExecutableMode.INVOKE);
|
||||
builder.withMethod("test", Collections.emptyList(), ExecutableMode.INVOKE);
|
||||
});
|
||||
assertThat(writeJson(hints)).isEqualTo(writeJson(hints2));
|
||||
}
|
||||
|
||||
private void assertEquals(String expectedString, ReflectionHints hints) throws JSONException {
|
||||
JSONAssert.assertEquals(expectedString, writeJson(hints), JSONCompareMode.STRICT);
|
||||
}
|
||||
|
||||
private String writeJson(ReflectionHints hints) {
|
||||
StringWriter out = new StringWriter();
|
||||
BasicJsonWriter writer = new BasicJsonWriter(out, "\t");
|
||||
ReflectionHintsWriter.INSTANCE.write(writer, hints);
|
||||
JSONAssert.assertEquals(expectedString, out.toString(), JSONCompareMode.NON_EXTENSIBLE);
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* 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.
|
||||
@@ -49,11 +49,11 @@ class ResourceHintsWriterTests {
|
||||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{ "pattern": "\\\\Qcom/example/test.properties\\\\E"},
|
||||
{ "pattern": "\\\\Q/\\\\E" },
|
||||
{ "pattern": "\\\\Qcom\\\\E"},
|
||||
{ "pattern": "\\\\Qcom/example\\\\E"},
|
||||
{ "pattern": "\\\\Qcom/example/another.properties\\\\E"}
|
||||
{ "pattern": "\\\\Qcom/example/another.properties\\\\E"},
|
||||
{ "pattern": "\\\\Qcom/example/test.properties\\\\E"}
|
||||
]
|
||||
}
|
||||
}""", hints);
|
||||
@@ -82,10 +82,10 @@ class ResourceHintsWriterTests {
|
||||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{ "pattern": "\\\\Qcom/example/\\\\E.*\\\\Q.properties\\\\E"},
|
||||
{ "pattern": "\\\\Q/\\\\E" },
|
||||
{ "pattern": "\\\\Qcom\\\\E"},
|
||||
{ "pattern": "\\\\Qcom/example\\\\E"}
|
||||
{ "pattern": "\\\\Qcom/example\\\\E"},
|
||||
{ "pattern": "\\\\Qcom/example/\\\\E.*\\\\Q.properties\\\\E"}
|
||||
]
|
||||
}
|
||||
}""", hints);
|
||||
@@ -99,9 +99,9 @@ class ResourceHintsWriterTests {
|
||||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{ "pattern": "\\\\Qstatic/\\\\E.*"},
|
||||
{ "pattern": "\\\\Q/\\\\E" },
|
||||
{ "pattern": "\\\\Qstatic\\\\E"}
|
||||
{ "pattern": "\\\\Qstatic\\\\E"},
|
||||
{ "pattern": "\\\\Qstatic/\\\\E.*"}
|
||||
]
|
||||
}
|
||||
}""", hints);
|
||||
@@ -116,13 +116,13 @@ class ResourceHintsWriterTests {
|
||||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{ "pattern": "\\\\Qcom/example/\\\\E.*\\\\Q.properties\\\\E"},
|
||||
{ "pattern": "\\\\Q/\\\\E"},
|
||||
{ "pattern": "\\\\Qcom\\\\E"},
|
||||
{ "pattern": "\\\\Qcom/example\\\\E"},
|
||||
{ "pattern": "\\\\Qorg/other/\\\\E.*\\\\Q.properties\\\\E"},
|
||||
{ "pattern": "\\\\Qcom/example/\\\\E.*\\\\Q.properties\\\\E"},
|
||||
{ "pattern": "\\\\Qorg\\\\E"},
|
||||
{ "pattern": "\\\\Qorg/other\\\\E"}
|
||||
{ "pattern": "\\\\Qorg/other\\\\E"},
|
||||
{ "pattern": "\\\\Qorg/other/\\\\E.*\\\\Q.properties\\\\E"}
|
||||
],
|
||||
"excludes": [
|
||||
{ "pattern": "\\\\Qcom/example/to-ignore.properties\\\\E"},
|
||||
@@ -140,10 +140,10 @@ class ResourceHintsWriterTests {
|
||||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{ "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Qcom/example/test.properties\\\\E"},
|
||||
{ "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Q/\\\\E"},
|
||||
{ "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Qcom\\\\E"},
|
||||
{ "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Qcom/example\\\\E"}
|
||||
{ "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Qcom/example\\\\E"},
|
||||
{ "condition": { "typeReachable": "com.example.Test"}, "pattern": "\\\\Qcom/example/test.properties\\\\E"}
|
||||
]
|
||||
}
|
||||
}""", hints);
|
||||
@@ -157,10 +157,10 @@ class ResourceHintsWriterTests {
|
||||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{ "pattern": "\\\\Qjava/lang/String.class\\\\E" },
|
||||
{ "pattern": "\\\\Q/\\\\E" },
|
||||
{ "pattern": "\\\\Qjava\\\\E" },
|
||||
{ "pattern": "\\\\Qjava/lang\\\\E" }
|
||||
{ "pattern": "\\\\Qjava/lang\\\\E" },
|
||||
{ "pattern": "\\\\Qjava/lang/String.class\\\\E" }
|
||||
]
|
||||
}
|
||||
}""", hints);
|
||||
@@ -169,8 +169,8 @@ class ResourceHintsWriterTests {
|
||||
@Test
|
||||
void registerResourceBundle() throws JSONException {
|
||||
ResourceHints hints = new ResourceHints();
|
||||
hints.registerResourceBundle("com.example.message");
|
||||
hints.registerResourceBundle("com.example.message2");
|
||||
hints.registerResourceBundle("com.example.message");
|
||||
assertEquals("""
|
||||
{
|
||||
"bundles": [
|
||||
@@ -184,7 +184,7 @@ class ResourceHintsWriterTests {
|
||||
StringWriter out = new StringWriter();
|
||||
BasicJsonWriter writer = new BasicJsonWriter(out, "\t");
|
||||
ResourceHintsWriter.INSTANCE.write(writer, hints);
|
||||
JSONAssert.assertEquals(expectedString, out.toString(), JSONCompareMode.NON_EXTENSIBLE);
|
||||
JSONAssert.assertEquals(expectedString, out.toString(), JSONCompareMode.STRICT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* 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.
|
||||
@@ -52,8 +52,8 @@ public class SerializationHintsWriterTests {
|
||||
@Test
|
||||
void shouldWriteMultipleHints() throws JSONException {
|
||||
SerializationHints hints = new SerializationHints()
|
||||
.registerType(TypeReference.of(String.class))
|
||||
.registerType(TypeReference.of(Environment.class));
|
||||
.registerType(TypeReference.of(Environment.class))
|
||||
.registerType(TypeReference.of(String.class));
|
||||
assertEquals("""
|
||||
[
|
||||
{ "name": "java.lang.String" },
|
||||
@@ -75,7 +75,7 @@ public class SerializationHintsWriterTests {
|
||||
StringWriter out = new StringWriter();
|
||||
BasicJsonWriter writer = new BasicJsonWriter(out, "\t");
|
||||
SerializationHintsWriter.INSTANCE.write(writer, hints);
|
||||
JSONAssert.assertEquals(expectedString, out.toString(), JSONCompareMode.NON_EXTENSIBLE);
|
||||
JSONAssert.assertEquals(expectedString, out.toString(), JSONCompareMode.STRICT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user