From eaf7a282506e3d89d6ae519ef4d716198b928ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 15 Dec 2023 16:55:13 +0100 Subject: [PATCH] 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 --- .../aot/hint/AbstractTypeReference.java | 4 + .../aot/hint/ExecutableHint.java | 17 ++++- .../aot/hint/TypeReference.java | 2 +- .../aot/nativex/ProxyHintsWriter.java | 17 ++++- .../aot/nativex/ReflectionHintsWriter.java | 16 ++-- .../aot/nativex/ResourceHintsWriter.java | 24 ++++-- .../aot/nativex/SerializationHintsWriter.java | 10 ++- .../aot/nativex/ProxyHintsWriterTests.java | 20 ++++- .../nativex/ReflectionHintsWriterTests.java | 75 ++++++++++++++++++- .../aot/nativex/ResourceHintsWriterTests.java | 32 ++++---- .../SerializationHintsWriterTests.java | 8 +- 11 files changed, 183 insertions(+), 42 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/aot/hint/AbstractTypeReference.java b/spring-core/src/main/java/org/springframework/aot/hint/AbstractTypeReference.java index 874ce2ad67..77c7834167 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/AbstractTypeReference.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/AbstractTypeReference.java @@ -79,6 +79,10 @@ public abstract class AbstractTypeReference implements TypeReference { protected abstract boolean isPrimitive(); + @Override + public int compareTo(TypeReference other) { + return this.getCanonicalName().compareToIgnoreCase(other.getCanonicalName()); + } @Override public boolean equals(@Nullable Object other) { diff --git a/spring-core/src/main/java/org/springframework/aot/hint/ExecutableHint.java b/spring-core/src/main/java/org/springframework/aot/hint/ExecutableHint.java index 3cf8fd7474..5d0c3a4d26 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/ExecutableHint.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/ExecutableHint.java @@ -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,8 +19,10 @@ package org.springframework.aot.hint; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; +import java.util.Comparator; import java.util.List; import java.util.function.Consumer; +import java.util.stream.Collectors; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -32,7 +34,7 @@ import org.springframework.util.Assert; * @author Stephane Nicoll * @since 6.0 */ -public final class ExecutableHint extends MemberHint { +public final class ExecutableHint extends MemberHint implements Comparable { private final List parameterTypes; @@ -91,6 +93,17 @@ public final class ExecutableHint extends MemberHint { return builder -> builder.withMode(mode); } + @Override + public int compareTo(ExecutableHint other) { + return Comparator.comparing(ExecutableHint::getName, String::compareToIgnoreCase) + .thenComparing(ExecutableHint::getParameterTypes, Comparator.comparingInt(List::size)) + .thenComparing(ExecutableHint::getParameterTypes, (params1, params2) -> { + String left = params1.stream().map(TypeReference::getCanonicalName).collect(Collectors.joining(",")); + String right = params2.stream().map(TypeReference::getCanonicalName).collect(Collectors.joining(",")); + return left.compareTo(right); + }).compare(this, other); + } + /** * Builder for {@link ExecutableHint}. */ diff --git a/spring-core/src/main/java/org/springframework/aot/hint/TypeReference.java b/spring-core/src/main/java/org/springframework/aot/hint/TypeReference.java index 6e222de0be..6bc2c8cf28 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/TypeReference.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/TypeReference.java @@ -29,7 +29,7 @@ import org.springframework.lang.Nullable; * @author Sebastien Deleuze * @since 6.0 */ -public interface TypeReference { +public interface TypeReference extends Comparable { /** * Return the fully qualified name of this type reference. 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 index 055a0d1160..51cd3132ef 100644 --- a/spring-core/src/main/java/org/springframework/aot/nativex/ProxyHintsWriter.java +++ b/spring-core/src/main/java/org/springframework/aot/nativex/ProxyHintsWriter.java @@ -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. @@ -16,11 +16,14 @@ 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 @@ -38,8 +41,18 @@ 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().map(this::toAttributes).toList()); + writer.writeArray(hints.jdkProxyHints().sorted(JDK_PROXY_HINT_COMPARATOR) + .map(this::toAttributes).toList()); } private Map toAttributes(JdkProxyHint hint) { diff --git a/spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsWriter.java b/spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsWriter.java index 8a2b3603b0..3d678b0d85 100644 --- a/spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsWriter.java +++ b/spring-core/src/main/java/org/springframework/aot/nativex/ReflectionHintsWriter.java @@ -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. @@ -17,6 +17,7 @@ package org.springframework.aot.nativex; import java.util.Collection; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -49,7 +50,9 @@ class ReflectionHintsWriter { public static final ReflectionHintsWriter INSTANCE = new ReflectionHintsWriter(); public void write(BasicJsonWriter writer, ReflectionHints hints) { - writer.writeArray(hints.typeHints().map(this::toAttributes).toList()); + writer.writeArray(hints.typeHints() + .sorted(Comparator.comparing(TypeHint::getType)) + .map(this::toAttributes).toList()); } private Map toAttributes(TypeHint hint) { @@ -58,7 +61,8 @@ class ReflectionHintsWriter { handleCondition(attributes, hint); handleCategories(attributes, hint.getMemberCategories()); handleFields(attributes, hint.fields()); - handleExecutables(attributes, Stream.concat(hint.constructors(), hint.methods()).toList()); + handleExecutables(attributes, Stream.concat( + hint.constructors(), hint.methods()).sorted().toList()); return attributes; } @@ -71,7 +75,9 @@ class ReflectionHintsWriter { } private void handleFields(Map attributes, Stream fields) { - addIfNotEmpty(attributes, "fields", fields.map(this::toAttributes).toList()); + addIfNotEmpty(attributes, "fields", fields + .sorted(Comparator.comparing(FieldHint::getName, String::compareToIgnoreCase)) + .map(this::toAttributes).toList()); } private Map toAttributes(FieldHint hint) { @@ -97,7 +103,7 @@ class ReflectionHintsWriter { } private void handleCategories(Map attributes, Set categories) { - categories.forEach(category -> { + categories.stream().sorted().forEach(category -> { switch (category) { case PUBLIC_FIELDS -> attributes.put("allPublicFields", true); case DECLARED_FIELDS -> attributes.put("allDeclaredFields", true); diff --git a/spring-core/src/main/java/org/springframework/aot/nativex/ResourceHintsWriter.java b/spring-core/src/main/java/org/springframework/aot/nativex/ResourceHintsWriter.java index 8db578d952..6829006e90 100644 --- a/spring-core/src/main/java/org/springframework/aot/nativex/ResourceHintsWriter.java +++ b/spring-core/src/main/java/org/springframework/aot/nativex/ResourceHintsWriter.java @@ -17,6 +17,7 @@ package org.springframework.aot.nativex; import java.util.Collection; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -44,6 +45,13 @@ class ResourceHintsWriter { public static final ResourceHintsWriter INSTANCE = new ResourceHintsWriter(); + private static final Comparator RESOURCE_PATTERN_HINT_COMPARATOR = + Comparator.comparing(ResourcePatternHint::getPattern); + + private static final Comparator RESOURCE_BUNDLE_HINT_COMPARATOR = + Comparator.comparing(ResourceBundleHint::getBaseName); + + public void write(BasicJsonWriter writer, ResourceHints hints) { Map attributes = new LinkedHashMap<>(); addIfNotEmpty(attributes, "resources", toAttributes(hints)); @@ -53,15 +61,21 @@ class ResourceHintsWriter { private Map toAttributes(ResourceHints hint) { Map attributes = new LinkedHashMap<>(); - addIfNotEmpty(attributes, "includes", hint.resourcePatternHints().map(ResourcePatternHints::getIncludes) - .flatMap(List::stream).distinct().map(this::toAttributes).toList()); - addIfNotEmpty(attributes, "excludes", hint.resourcePatternHints().map(ResourcePatternHints::getExcludes) - .flatMap(List::stream).distinct().map(this::toAttributes).toList()); + addIfNotEmpty(attributes, "includes", hint.resourcePatternHints() + .map(ResourcePatternHints::getIncludes).flatMap(List::stream).distinct() + .sorted(RESOURCE_PATTERN_HINT_COMPARATOR) + .map(this::toAttributes).toList()); + addIfNotEmpty(attributes, "excludes", hint.resourcePatternHints() + .map(ResourcePatternHints::getExcludes).flatMap(List::stream).distinct() + .sorted(RESOURCE_PATTERN_HINT_COMPARATOR) + .map(this::toAttributes).toList()); return attributes; } private void handleResourceBundles(Map attributes, Stream resourceBundles) { - addIfNotEmpty(attributes, "bundles", resourceBundles.map(this::toAttributes).toList()); + addIfNotEmpty(attributes, "bundles", resourceBundles + .sorted(RESOURCE_BUNDLE_HINT_COMPARATOR) + .map(this::toAttributes).toList()); } private Map toAttributes(ResourceBundleHint hint) { diff --git a/spring-core/src/main/java/org/springframework/aot/nativex/SerializationHintsWriter.java b/spring-core/src/main/java/org/springframework/aot/nativex/SerializationHintsWriter.java index cd0f6c802d..73b2524851 100644 --- a/spring-core/src/main/java/org/springframework/aot/nativex/SerializationHintsWriter.java +++ b/spring-core/src/main/java/org/springframework/aot/nativex/SerializationHintsWriter.java @@ -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. @@ -16,6 +16,7 @@ package org.springframework.aot.nativex; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.Map; @@ -38,8 +39,13 @@ class SerializationHintsWriter { public static final SerializationHintsWriter INSTANCE = new SerializationHintsWriter(); + private static final Comparator JAVA_SERIALIZATION_HINT_COMPARATOR = + Comparator.comparing(JavaSerializationHint::getType); + public void write(BasicJsonWriter writer, SerializationHints hints) { - writer.writeArray(hints.javaSerializationHints().map(this::toAttributes).toList()); + writer.writeArray(hints.javaSerializationHints() + .sorted(JAVA_SERIALIZATION_HINT_COMPARATOR) + .map(this::toAttributes).toList()); } private Map toAttributes(JavaSerializationHint serializationHint) { diff --git a/spring-core/src/test/java/org/springframework/aot/nativex/ProxyHintsWriterTests.java b/spring-core/src/test/java/org/springframework/aot/nativex/ProxyHintsWriterTests.java index d4a624f690..6a65db7e9d 100644 --- a/spring-core/src/test/java/org/springframework/aot/nativex/ProxyHintsWriterTests.java +++ b/spring-core/src/test/java/org/springframework/aot/nativex/ProxyHintsWriterTests.java @@ -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 { diff --git a/spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java b/spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java index bb17e5a832..e60f86b54c 100644 --- a/spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java +++ b/spring-core/src/test/java/org/springframework/aot/nativex/ReflectionHintsWriterTests.java @@ -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(); } diff --git a/spring-core/src/test/java/org/springframework/aot/nativex/ResourceHintsWriterTests.java b/spring-core/src/test/java/org/springframework/aot/nativex/ResourceHintsWriterTests.java index a07a52191f..b3fef587ef 100644 --- a/spring-core/src/test/java/org/springframework/aot/nativex/ResourceHintsWriterTests.java +++ b/spring-core/src/test/java/org/springframework/aot/nativex/ResourceHintsWriterTests.java @@ -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); } } diff --git a/spring-core/src/test/java/org/springframework/aot/nativex/SerializationHintsWriterTests.java b/spring-core/src/test/java/org/springframework/aot/nativex/SerializationHintsWriterTests.java index b10d7a595f..913a8f89a2 100644 --- a/spring-core/src/test/java/org/springframework/aot/nativex/SerializationHintsWriterTests.java +++ b/spring-core/src/test/java/org/springframework/aot/nativex/SerializationHintsWriterTests.java @@ -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); } }