diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveClassBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveClassBuildItem.java index d71a00b8e0eab..4e6402a005838 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveClassBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveClassBuildItem.java @@ -7,6 +7,7 @@ import java.util.List; import io.quarkus.builder.item.MultiBuildItem; +import io.quarkus.logging.Log; /** * Used to register a class for reflection in native mode @@ -15,8 +16,10 @@ public final class ReflectiveClassBuildItem extends MultiBuildItem { private final List className; private final boolean methods; + private final boolean queryMethods; private final boolean fields; private final boolean constructors; + private final boolean queryConstructors; private final boolean weak; private final boolean serialization; private final boolean unsafeAllocated; @@ -38,7 +41,8 @@ public static Builder builder(String... classNames) { return new Builder().className(classNames); } - private ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, boolean weak, boolean serialization, + private ReflectiveClassBuildItem(boolean constructors, boolean queryConstructors, boolean methods, boolean queryMethods, + boolean fields, boolean weak, boolean serialization, boolean unsafeAllocated, Class... classes) { List names = new ArrayList<>(); for (Class i : classes) { @@ -49,8 +53,24 @@ private ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean } this.className = names; this.methods = methods; + if (methods && queryMethods) { + Log.warnf( + "Both methods and queryMethods are set to true for classes: %s. queryMethods is redundant and will be ignored", + String.join(", ", names)); + this.queryMethods = false; + } else { + this.queryMethods = queryMethods; + } this.fields = fields; this.constructors = constructors; + if (methods && queryMethods) { + Log.warnf( + "Both constructors and queryConstructors are set to true for classes: %s. queryConstructors is redundant and will be ignored", + String.join(", ", names)); + this.queryConstructors = false; + } else { + this.queryConstructors = queryConstructors; + } this.weak = weak; this.serialization = serialization; this.unsafeAllocated = unsafeAllocated; @@ -74,7 +94,7 @@ public ReflectiveClassBuildItem(boolean methods, boolean fields, Class... cla */ @Deprecated(since = "3.0", forRemoval = true) public ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, Class... classes) { - this(constructors, methods, fields, false, false, false, classes); + this(constructors, false, methods, false, fields, false, false, false, classes); } /** @@ -92,7 +112,7 @@ public ReflectiveClassBuildItem(boolean methods, boolean fields, String... class */ @Deprecated(since = "3.0", forRemoval = true) public ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, String... classNames) { - this(constructors, methods, fields, false, false, false, classNames); + this(constructors, false, methods, false, fields, false, false, false, classNames); } /** @@ -102,7 +122,7 @@ public ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean f @Deprecated(since = "3.0", forRemoval = true) public ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, boolean serialization, String... classNames) { - this(constructors, methods, fields, false, serialization, false, classNames); + this(constructors, false, methods, false, fields, false, serialization, false, classNames); } public static ReflectiveClassBuildItem weakClass(String... classNames) { @@ -123,7 +143,8 @@ public static ReflectiveClassBuildItem serializationClass(String... classNames) return ReflectiveClassBuildItem.builder(classNames).serialization().build(); } - ReflectiveClassBuildItem(boolean constructors, boolean methods, boolean fields, boolean weak, boolean serialization, + ReflectiveClassBuildItem(boolean constructors, boolean queryConstructors, boolean methods, boolean queryMethods, + boolean fields, boolean weak, boolean serialization, boolean unsafeAllocated, String... className) { for (String i : className) { if (i == null) { @@ -132,8 +153,24 @@ public static ReflectiveClassBuildItem serializationClass(String... classNames) } this.className = Arrays.asList(className); this.methods = methods; + if (methods && queryMethods) { + Log.warnf( + "Both methods and queryMethods are set to true for classes: %s. queryMethods is redundant and will be ignored", + String.join(", ", className)); + this.queryMethods = false; + } else { + this.queryMethods = queryMethods; + } this.fields = fields; this.constructors = constructors; + if (methods && queryMethods) { + Log.warnf( + "Both constructors and queryConstructors are set to true for classes: %s. queryConstructors is redundant and will be ignored", + String.join(", ", className)); + this.queryConstructors = false; + } else { + this.queryConstructors = queryConstructors; + } this.weak = weak; this.serialization = serialization; this.unsafeAllocated = unsafeAllocated; @@ -147,6 +184,10 @@ public boolean isMethods() { return methods; } + public boolean isQueryMethods() { + return queryMethods; + } + public boolean isFields() { return fields; } @@ -155,6 +196,10 @@ public boolean isConstructors() { return constructors; } + public boolean isQueryConstructors() { + return queryConstructors; + } + /** * @deprecated As of GraalVM 21.2 finalFieldsWritable is no longer needed when registering fields for reflection. This will * be removed in a future verion of Quarkus. @@ -179,7 +224,9 @@ public boolean isUnsafeAllocated() { public static class Builder { private String[] className; private boolean constructors = true; + private boolean queryConstructors; private boolean methods; + private boolean queryMethods; private boolean fields; private boolean weak; private boolean serialization; @@ -202,6 +249,15 @@ public Builder constructors() { return constructors(true); } + public Builder queryConstructors(boolean queryConstructors) { + this.queryConstructors = queryConstructors; + return this; + } + + public Builder queryConstructors() { + return queryConstructors(true); + } + public Builder methods(boolean methods) { this.methods = methods; return this; @@ -211,6 +267,15 @@ public Builder methods() { return methods(true); } + public Builder queryMethods(boolean queryMethods) { + this.queryMethods = queryMethods; + return this; + } + + public Builder queryMethods() { + return queryMethods(true); + } + public Builder fields(boolean fields) { this.fields = fields; return this; @@ -257,7 +322,8 @@ public Builder unsafeAllocated() { } public ReflectiveClassBuildItem build() { - return new ReflectiveClassBuildItem(constructors, methods, fields, weak, serialization, unsafeAllocated, className); + return new ReflectiveClassBuildItem(constructors, queryConstructors, methods, queryMethods, fields, weak, + serialization, unsafeAllocated, className); } } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageReflectConfigStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageReflectConfigStep.java index cd04106f20330..5800346551893 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageReflectConfigStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageReflectConfigStep.java @@ -40,7 +40,8 @@ void generateReflectConfig(BuildProducer reflectConf forcedNonWeakClasses.add(nonWeakReflectiveClassBuildItem.getClassName()); } for (ReflectiveClassBuildItem i : reflectiveClassBuildItems) { - addReflectiveClass(reflectiveClasses, forcedNonWeakClasses, i.isConstructors(), i.isMethods(), i.isFields(), + addReflectiveClass(reflectiveClasses, forcedNonWeakClasses, i.isConstructors(), i.isQueryConstructors(), + i.isMethods(), i.isQueryMethods(), i.isFields(), i.isWeak(), i.isSerialization(), i.isUnsafeAllocated(), i.getClassNames().toArray(new String[0])); } for (ReflectiveFieldBuildItem i : reflectiveFields) { @@ -51,7 +52,7 @@ void generateReflectConfig(BuildProducer reflectConf } for (ServiceProviderBuildItem i : serviceProviderBuildItems) { - addReflectiveClass(reflectiveClasses, forcedNonWeakClasses, true, false, false, false, false, false, + addReflectiveClass(reflectiveClasses, forcedNonWeakClasses, true, false, false, false, false, false, false, false, i.providers().toArray(new String[] {})); } @@ -76,30 +77,40 @@ void generateReflectConfig(BuildProducer reflectConf } if (info.constructors) { json.put("allDeclaredConstructors", true); - } else if (!info.ctorSet.isEmpty()) { - for (ReflectiveMethodBuildItem ctor : info.ctorSet) { - JsonObjectBuilder methodObject = Json.object(); - methodObject.put("name", ctor.getName()); - JsonArrayBuilder paramsArray = Json.array(); - for (int i = 0; i < ctor.getParams().length; ++i) { - paramsArray.add(ctor.getParams()[i]); + } else { + if (info.queryConstructors) { + json.put("queryAllDeclaredConstructors", true); + } + if (!info.ctorSet.isEmpty()) { + for (ReflectiveMethodBuildItem ctor : info.ctorSet) { + JsonObjectBuilder methodObject = Json.object(); + methodObject.put("name", ctor.getName()); + JsonArrayBuilder paramsArray = Json.array(); + for (int i = 0; i < ctor.getParams().length; ++i) { + paramsArray.add(ctor.getParams()[i]); + } + methodObject.put("parameterTypes", paramsArray); + methodsArray.add(methodObject); } - methodObject.put("parameterTypes", paramsArray); - methodsArray.add(methodObject); } } if (info.methods) { json.put("allDeclaredMethods", true); - } else if (!info.methodSet.isEmpty()) { - for (ReflectiveMethodBuildItem method : info.methodSet) { - JsonObjectBuilder methodObject = Json.object(); - methodObject.put("name", method.getName()); - JsonArrayBuilder paramsArray = Json.array(); - for (int i = 0; i < method.getParams().length; ++i) { - paramsArray.add(method.getParams()[i]); + } else { + if (info.queryMethods) { + json.put("queryAllDeclaredMethods", true); + } + if (!info.methodSet.isEmpty()) { + for (ReflectiveMethodBuildItem method : info.methodSet) { + JsonObjectBuilder methodObject = Json.object(); + methodObject.put("name", method.getName()); + JsonArrayBuilder paramsArray = Json.array(); + for (int i = 0; i < method.getParams().length; ++i) { + paramsArray.add(method.getParams()[i]); + } + methodObject.put("parameterTypes", paramsArray); + methodsArray.add(methodObject); } - methodObject.put("parameterTypes", paramsArray); - methodsArray.add(methodObject); } } if (!methodsArray.isEmpty()) { @@ -145,22 +156,28 @@ public void addReflectiveMethod(Map reflectiveClasses, R } public void addReflectiveClass(Map reflectiveClasses, Set forcedNonWeakClasses, - boolean constructors, boolean method, - boolean fields, boolean weak, boolean serialization, boolean unsafeAllocated, + boolean constructors, boolean queryConstructors, boolean method, + boolean queryMethods, boolean fields, boolean weak, boolean serialization, boolean unsafeAllocated, String... className) { for (String cl : className) { ReflectionInfo existing = reflectiveClasses.get(cl); if (existing == null) { String typeReachable = (!forcedNonWeakClasses.contains(cl) && weak) ? cl : null; - reflectiveClasses.put(cl, new ReflectionInfo(constructors, method, fields, + reflectiveClasses.put(cl, new ReflectionInfo(constructors, queryConstructors, method, queryMethods, fields, typeReachable, serialization, unsafeAllocated)); } else { if (constructors) { existing.constructors = true; } + if (queryConstructors) { + existing.queryConstructors = true; + } if (method) { existing.methods = true; } + if (queryMethods) { + existing.queryMethods = true; + } if (fields) { existing.fields = true; } @@ -185,7 +202,9 @@ public void addReflectiveField(Map reflectiveClasses, Re static final class ReflectionInfo { boolean constructors; + boolean queryConstructors; boolean methods; + boolean queryMethods; boolean fields; boolean serialization; boolean unsafeAllocated; @@ -195,15 +214,18 @@ static final class ReflectionInfo { Set ctorSet = new HashSet<>(); private ReflectionInfo() { - this(false, false, false, null, false, false); + this(false, false, false, false, false, null, false, false); } - private ReflectionInfo(boolean constructors, boolean methods, boolean fields, String typeReachable, + private ReflectionInfo(boolean constructors, boolean queryConstructors, boolean methods, boolean queryMethods, + boolean fields, String typeReachable, boolean serialization, boolean unsafeAllocated) { this.methods = methods; + this.queryMethods = queryMethods; this.fields = fields; this.typeReachable = typeReachable; this.constructors = constructors; + this.queryConstructors = queryConstructors; this.serialization = serialization; this.unsafeAllocated = unsafeAllocated; }