Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend ReflectiveClassBuildItem to support queryOnly option #42035

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@
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
*/
public final class ReflectiveClassBuildItem extends MultiBuildItem {

// The names of the classes that should be registered for reflection
private final List<String> 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;
Expand All @@ -38,7 +42,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<String> names = new ArrayList<>();
for (Class<?> i : classes) {
Expand All @@ -49,8 +54,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;
Expand All @@ -74,7 +95,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);
}

/**
Expand All @@ -92,7 +113,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);
}

/**
Expand All @@ -102,7 +123,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) {
Expand All @@ -123,7 +144,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) {
Expand All @@ -132,8 +154,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;
Expand All @@ -147,6 +185,10 @@ public boolean isMethods() {
return methods;
}

public boolean isQueryMethods() {
return queryMethods;
}

public boolean isFields() {
return fields;
}
Expand All @@ -155,6 +197,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.
Expand All @@ -179,7 +225,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;
Expand All @@ -193,6 +241,10 @@ public Builder className(String[] className) {
return this;
}

/**
* Configures whether constructors should be registered for reflection (true by default).
* Setting this enables getting all declared constructors for the class as well as invoking them reflectively.
*/
public Builder constructors(boolean constructors) {
this.constructors = constructors;
return this;
Expand All @@ -202,6 +254,23 @@ public Builder constructors() {
return constructors(true);
}

/**
* Configures whether constructors should be registered for reflection, for query purposes only.
* Setting this enables getting all declared constructors for the class but does not allow invoking them reflectively.
*/
public Builder queryConstructors(boolean queryConstructors) {
this.queryConstructors = queryConstructors;
return this;
}

public Builder queryConstructors() {
return queryConstructors(true);
}

/**
* Configures whether methods should be registered for reflection.
* Setting this enables getting all declared methods for the class as well as invoking them reflectively.
*/
public Builder methods(boolean methods) {
this.methods = methods;
return this;
Expand All @@ -211,6 +280,23 @@ public Builder methods() {
return methods(true);
}

/**
* Configures whether methods should be registered for reflection, for query purposes only.
* Setting this enables getting all declared methods for the class but does not allow invoking them reflectively.
*/
public Builder queryMethods(boolean queryMethods) {
this.queryMethods = queryMethods;
return this;
}

public Builder queryMethods() {
return queryMethods(true);
}

/**
* Configures whether fields should be registered for reflection.
* Setting this enables getting all declared fields for the class as well as accessing them reflectively.
*/
public Builder fields(boolean fields) {
this.fields = fields;
return this;
Expand Down Expand Up @@ -238,6 +324,9 @@ public Builder weak() {
return weak(true);
}

/**
* Configures whether serialization support should be enabled for the class.
*/
public Builder serialization(boolean serialization) {
this.serialization = serialization;
return this;
Expand All @@ -247,6 +336,9 @@ public Builder serialization() {
return serialization(true);
}

/**
* Configures whether the class can be allocated in an unsafe manner (through JNI).
*/
public Builder unsafeAllocated(boolean unsafeAllocated) {
this.unsafeAllocated = unsafeAllocated;
return this;
Expand All @@ -257,7 +349,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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ void generateReflectConfig(BuildProducer<GeneratedResourceBuildItem> 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) {
Expand All @@ -51,7 +52,7 @@ void generateReflectConfig(BuildProducer<GeneratedResourceBuildItem> 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[] {}));
}

Expand All @@ -76,30 +77,40 @@ void generateReflectConfig(BuildProducer<GeneratedResourceBuildItem> 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()) {
Expand Down Expand Up @@ -145,22 +156,28 @@ public void addReflectiveMethod(Map<String, ReflectionInfo> reflectiveClasses, R
}

public void addReflectiveClass(Map<String, ReflectionInfo> reflectiveClasses, Set<String> 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;
}
Expand All @@ -185,7 +202,9 @@ public void addReflectiveField(Map<String, ReflectionInfo> reflectiveClasses, Re

static final class ReflectionInfo {
boolean constructors;
boolean queryConstructors;
boolean methods;
boolean queryMethods;
boolean fields;
boolean serialization;
boolean unsafeAllocated;
Expand All @@ -195,15 +214,18 @@ static final class ReflectionInfo {
Set<ReflectiveMethodBuildItem> 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;
}
Expand Down
Loading