diff --git a/src/main/java/org/mikeneck/graalvm/config/ClassUsage.java b/src/main/java/org/mikeneck/graalvm/config/ClassUsage.java index f09ff70..afa353d 100644 --- a/src/main/java/org/mikeneck/graalvm/config/ClassUsage.java +++ b/src/main/java/org/mikeneck/graalvm/config/ClassUsage.java @@ -57,6 +57,26 @@ public class ClassUsage implements Comparable, MergeableConfig queriedMethods = Collections.emptySortedSet(); + @SuppressWarnings("unused") public ClassUsage() {} @@ -71,7 +91,12 @@ private ClassUsage( @Nullable Boolean allPublicConstructors, @Nullable Boolean allPublicFields, @Nullable Boolean allDeclaredClasses, - @Nullable Boolean allPublicClasses) { + @Nullable Boolean allPublicClasses, + @Nullable Boolean queryAllDeclaredConstructors, + @Nullable Boolean queryAllPublicConstructors, + @Nullable Boolean queryAllDeclaredMethods, + @Nullable Boolean queryAllPublicMethods, + @Nullable SortedSet queriedMethods) { this.name = name; this.methods = methods; this.fields = fields; @@ -83,6 +108,11 @@ private ClassUsage( this.allPublicFields = allPublicFields; this.allDeclaredClasses = allDeclaredClasses; this.allPublicClasses = allPublicClasses; + this.queryAllDeclaredConstructors = queryAllDeclaredConstructors; + this.queryAllPublicConstructors = queryAllPublicConstructors; + this.queryAllDeclaredMethods = queryAllDeclaredMethods; + this.queryAllPublicMethods = queryAllPublicMethods; + this.queriedMethods = queriedMethods; } public ClassUsage( @@ -180,7 +210,12 @@ public boolean equals(Object o) { && Objects.equals(allPublicConstructors, that.allPublicConstructors) && Objects.equals(allPublicFields, that.allPublicFields) && Objects.equals(allDeclaredClasses, that.allDeclaredClasses) - && Objects.equals(allPublicClasses, that.allPublicClasses); + && Objects.equals(allPublicClasses, that.allPublicClasses) + && Objects.equals(queryAllDeclaredConstructors, that.queryAllDeclaredConstructors) + && Objects.equals(queryAllPublicConstructors, that.queryAllPublicConstructors) + && Objects.equals(queryAllDeclaredMethods, that.queryAllDeclaredMethods) + && Objects.equals(queryAllPublicMethods, that.queryAllPublicMethods) + && Objects.equals(queriedMethods, that.queriedMethods); } @Override @@ -196,7 +231,12 @@ public int hashCode() { allPublicConstructors, allPublicFields, allDeclaredClasses, - allPublicClasses); + allPublicClasses, + queryAllDeclaredConstructors, + queryAllPublicConstructors, + queryAllDeclaredMethods, + queryAllPublicMethods, + queriedMethods); } @SuppressWarnings("StringBufferReplaceableByString") @@ -214,6 +254,11 @@ public String toString() { sb.append(", allPublicFields=").append(allPublicFields); sb.append(", allDeclaredClasses=").append(allDeclaredClasses); sb.append(", allPublicClasses=").append(allPublicClasses); + sb.append(", queryAllDeclaredConstructors=").append(queryAllDeclaredConstructors); + sb.append(", queryAllPublicConstructors=").append(queryAllPublicConstructors); + sb.append(", queryAllDeclaredMethods=").append(queryAllDeclaredMethods); + sb.append(", queryAllPublicMethods=").append(queryAllPublicMethods); + sb.append(", queriedMethods=").append(queriedMethods); sb.append('}'); return sb.toString(); } @@ -232,6 +277,13 @@ public ClassUsage mergeWith(ClassUsage other) { TreeSet newMethods = new TreeSet<>(this.methods); newMethods.addAll(other.methods); FieldUsages newFields = this.fields.mergeWith(other.fields); + TreeSet newQueriedMethods = new TreeSet<>(); + if (this.queriedMethods != null) { + newQueriedMethods.addAll(this.queriedMethods); + } + if (other.queriedMethods != null) { + newQueriedMethods.addAll(other.queriedMethods); + } return new ClassUsage( this.name, newMethods, @@ -243,6 +295,13 @@ public ClassUsage mergeWith(ClassUsage other) { BooleanMergeable.mergeBoolean(this.allPublicConstructors, other.allPublicConstructors), BooleanMergeable.mergeBoolean(this.allPublicFields, other.allPublicFields), BooleanMergeable.mergeBoolean(this.allDeclaredClasses, other.allDeclaredClasses), - BooleanMergeable.mergeBoolean(this.allPublicClasses, other.allPublicClasses)); + BooleanMergeable.mergeBoolean(this.allPublicClasses, other.allPublicClasses), + BooleanMergeable.mergeBoolean( + this.queryAllDeclaredConstructors, other.queryAllDeclaredConstructors), + BooleanMergeable.mergeBoolean( + this.queryAllPublicConstructors, other.queryAllPublicConstructors), + BooleanMergeable.mergeBoolean(this.queryAllDeclaredMethods, other.queryAllDeclaredMethods), + BooleanMergeable.mergeBoolean(this.queryAllPublicMethods, other.queryAllPublicMethods), + newQueriedMethods); } } diff --git a/src/main/java/org/mikeneck/graalvm/config/ProxyUsage.java b/src/main/java/org/mikeneck/graalvm/config/ProxyUsage.java index fc4c600..00db49f 100644 --- a/src/main/java/org/mikeneck/graalvm/config/ProxyUsage.java +++ b/src/main/java/org/mikeneck/graalvm/config/ProxyUsage.java @@ -1,11 +1,20 @@ package org.mikeneck.graalvm.config; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.node.ArrayNode; +import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.TreeSet; import org.jetbrains.annotations.NotNull; +@JsonDeserialize(using = ProxyUsage.ProxyUsageDeserializer.class) public class ProxyUsage extends TreeSet implements Comparable { public ProxyUsage() { @@ -45,4 +54,31 @@ public int compareTo(@NotNull ProxyUsage o) { } return thatIterator.hasNext() ? -1 : 0; } + + static class ProxyUsageDeserializer extends JsonDeserializer { + private final ObjectMapper mapper = new ObjectMapper(); + + @Override + public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String[] interfaces = + mapper + .readerForListOf(String.class) + .readValue(findArray(p.getCodec().readTree(p)), String[].class); + return new ProxyUsage(interfaces); + } + + private ArrayNode findArray(TreeNode tree) { + if (tree.isArray()) { + return (ArrayNode) tree; + } + if (tree.isObject()) { + // new format from GraalVM 21.3.0 + TreeNode interfaces = tree.get("interfaces"); + if (interfaces != null && interfaces.isArray()) { + return (ArrayNode) interfaces; + } + } + throw new IllegalArgumentException(); + } + } } diff --git a/src/test/java/org/mikeneck/graalvm/config/ProxyConfigTest.java b/src/test/java/org/mikeneck/graalvm/config/ProxyConfigTest.java index fa16b9a..1bed94c 100644 --- a/src/test/java/org/mikeneck/graalvm/config/ProxyConfigTest.java +++ b/src/test/java/org/mikeneck/graalvm/config/ProxyConfigTest.java @@ -111,4 +111,14 @@ void emptyMergedWithEmptyBecomesEmpty() { assertThat(proxyConfig).isEqualTo(Collections.emptySortedSet()); } + + /** GraalVM 21.3.0 generates proxy-config in new format */ + @Test + void graal213() throws IOException { + try (InputStream inputStream = reader.configJsonResource("config/proxy-config-4.json")) { + ProxyConfig proxyConfig = objectMapper.readValue(inputStream, ProxyConfig.class); + assertThat(proxyConfig) + .contains(new ProxyUsage("com.example.Printer", "com.example.ExitCode")); + } + } } diff --git a/src/test/java/org/mikeneck/graalvm/config/ReflectConfigTest.java b/src/test/java/org/mikeneck/graalvm/config/ReflectConfigTest.java index 18b3c3f..fba81e3 100644 --- a/src/test/java/org/mikeneck/graalvm/config/ReflectConfigTest.java +++ b/src/test/java/org/mikeneck/graalvm/config/ReflectConfigTest.java @@ -6,11 +6,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; import org.jetbrains.annotations.Nullable; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DynamicTest; @@ -276,4 +272,24 @@ Iterable case111() throws IOException { return tests; } } + + /** + * GraalVM 21.3.0 added the {@code queriedMethods} field into the class usage + * + * @see Official example config file + */ + @Test + void graal213() throws IOException { + ClassUsage expected = new ClassUsage("org.graalvm.Example"); + expected.queryAllDeclaredConstructors = true; + expected.queriedMethods = new TreeSet<>(); + expected.queriedMethods.add(new MethodUsage("queriedOnlyMethod")); + + try (InputStream inputStream = reader.configJsonResource("config/reflect-config-3.json")) { + ReflectConfig reflectConfig = objectMapper.readValue(inputStream, ReflectConfig.class); + assertThat(reflectConfig).contains(expected); + } + } } diff --git a/src/test/resources/config/proxy-config-4.json b/src/test/resources/config/proxy-config-4.json new file mode 100644 index 0000000..d82aedc --- /dev/null +++ b/src/test/resources/config/proxy-config-4.json @@ -0,0 +1,5 @@ +[ + { + "interfaces":["com.example.Printer","com.example.ExitCode"]} + +] diff --git a/src/test/resources/config/reflect-config-3.json b/src/test/resources/config/reflect-config-3.json new file mode 100644 index 0000000..332d2fa --- /dev/null +++ b/src/test/resources/config/reflect-config-3.json @@ -0,0 +1,5 @@ +[{ + "name": "org.graalvm.Example", + "queryAllDeclaredConstructors": true, + "queriedMethods": [{"name":"queriedOnlyMethod", "parameterTypes":[]}] +}]