Skip to content

Commit

Permalink
Add conditions to optional classes to register
Browse files Browse the repository at this point in the history
  • Loading branch information
essobedo authored and zakkak committed Dec 15, 2022
1 parent 373b61f commit 67a776e
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.quarkus.deployment.builditem.nativeimage;

import io.quarkus.builder.item.MultiBuildItem;

/**
* Used to define a condition to register a class for reflection in native mode only when a specific type is reachable
*/
public final class ReflectiveClassConditionBuildItem extends MultiBuildItem {

private final String className;
private final String typeReachable;

public ReflectiveClassConditionBuildItem(Class<?> className, String typeReachable) {
this(className.getName(), typeReachable);
}

public ReflectiveClassConditionBuildItem(String className, String typeReachable) {
this.className = className;
this.typeReachable = typeReachable;
}

public String getClassName() {
return className;
}

public String getTypeReachable() {
return typeReachable;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ForceNonWeakReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassConditionBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveFieldBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
Expand All @@ -29,7 +30,8 @@ void generateReflectConfig(BuildProducer<GeneratedResourceBuildItem> reflectConf
List<ReflectiveFieldBuildItem> reflectiveFields,
List<ReflectiveClassBuildItem> reflectiveClassBuildItems,
List<ForceNonWeakReflectiveClassBuildItem> nonWeakReflectiveClassBuildItems,
List<ServiceProviderBuildItem> serviceProviderBuildItems) {
List<ServiceProviderBuildItem> serviceProviderBuildItems,
List<ReflectiveClassConditionBuildItem> reflectiveClassConditionBuildItems) {

final Map<String, ReflectionInfo> reflectiveClasses = new LinkedHashMap<>();
final Set<String> forcedNonWeakClasses = new HashSet<>();
Expand All @@ -52,20 +54,29 @@ void generateReflectConfig(BuildProducer<GeneratedResourceBuildItem> reflectConf
i.providers().toArray(new String[] {}));
}

// Perform this as last step, since it augments the already added reflective classes
for (ReflectiveClassConditionBuildItem i : reflectiveClassConditionBuildItems) {
reflectiveClasses.computeIfPresent(i.getClassName(), (key, value) -> {
value.typeReachable = i.getTypeReachable();
return value;
});
}

JsonArrayBuilder root = Json.array();
for (Map.Entry<String, ReflectionInfo> entry : reflectiveClasses.entrySet()) {
JsonObjectBuilder json = Json.object();

json.put("name", entry.getKey());

if (entry.getValue().weak) {
json.put("condition", Json.object().put("typeReachable", entry.getKey()));
ReflectionInfo info = entry.getValue();
if (info.typeReachable != null) {
json.put("condition", Json.object().put("typeReachable", info.typeReachable));
}
if (entry.getValue().constructors) {
if (info.constructors) {
json.put("allDeclaredConstructors", true);
} else if (!entry.getValue().ctorSet.isEmpty()) {
} else if (!info.ctorSet.isEmpty()) {
JsonArrayBuilder methodsArray = Json.array();
for (ReflectiveMethodBuildItem ctor : entry.getValue().ctorSet) {
for (ReflectiveMethodBuildItem ctor : info.ctorSet) {
JsonObjectBuilder methodObject = Json.object();
methodObject.put("name", ctor.getName());
JsonArrayBuilder paramsArray = Json.array();
Expand All @@ -77,11 +88,11 @@ void generateReflectConfig(BuildProducer<GeneratedResourceBuildItem> reflectConf
}
json.put("methods", methodsArray);
}
if (entry.getValue().methods) {
if (info.methods) {
json.put("allDeclaredMethods", true);
} else if (!entry.getValue().methodSet.isEmpty()) {
} else if (!info.methodSet.isEmpty()) {
JsonArrayBuilder methodsArray = Json.array();
for (ReflectiveMethodBuildItem method : entry.getValue().methodSet) {
for (ReflectiveMethodBuildItem method : info.methodSet) {
JsonObjectBuilder methodObject = Json.object();
methodObject.put("name", method.getName());
JsonArrayBuilder paramsArray = Json.array();
Expand All @@ -93,11 +104,11 @@ void generateReflectConfig(BuildProducer<GeneratedResourceBuildItem> reflectConf
}
json.put("methods", methodsArray);
}
if (entry.getValue().fields) {
if (info.fields) {
json.put("allDeclaredFields", true);
} else if (!entry.getValue().fieldSet.isEmpty()) {
} else if (!info.fieldSet.isEmpty()) {
JsonArrayBuilder fieldsArray = Json.array();
for (String fieldName : entry.getValue().fieldSet) {
for (String fieldName : info.fieldSet) {
JsonObjectBuilder field = Json.object();
field.put("name", fieldName);
fieldsArray.add(field);
Expand All @@ -121,7 +132,7 @@ public void addReflectiveMethod(Map<String, ReflectionInfo> reflectiveClasses, R
String cl = methodInfo.getDeclaringClass();
ReflectionInfo existing = reflectiveClasses.get(cl);
if (existing == null) {
reflectiveClasses.put(cl, existing = new ReflectionInfo(false, false, false, false, false));
reflectiveClasses.put(cl, existing = new ReflectionInfo());
}
if (methodInfo.getName().equals("<init>")) {
existing.ctorSet.add(methodInfo);
Expand All @@ -137,8 +148,9 @@ public void addReflectiveClass(Map<String, ReflectionInfo> reflectiveClasses, Se
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,
!forcedNonWeakClasses.contains(cl) && weak, serialization));
typeReachable, serialization));
} else {
if (constructors) {
existing.constructors = true;
Expand All @@ -160,7 +172,7 @@ public void addReflectiveField(Map<String, ReflectionInfo> reflectiveClasses, Re
String cl = fieldInfo.getDeclaringClass();
ReflectionInfo existing = reflectiveClasses.get(cl);
if (existing == null) {
reflectiveClasses.put(cl, existing = new ReflectionInfo(false, false, false, false, false));
reflectiveClasses.put(cl, existing = new ReflectionInfo());
}
existing.fieldSet.add(fieldInfo.getName());
}
Expand All @@ -169,17 +181,22 @@ static final class ReflectionInfo {
boolean constructors;
boolean methods;
boolean fields;
boolean weak;
boolean serialization;
String typeReachable;
Set<String> fieldSet = new HashSet<>();
Set<ReflectiveMethodBuildItem> methodSet = new HashSet<>();
Set<ReflectiveMethodBuildItem> ctorSet = new HashSet<>();

private ReflectionInfo(boolean constructors, boolean methods, boolean fields, boolean weak, boolean serialization) {
private ReflectionInfo() {
this(false, false, false, null, false);
}

private ReflectionInfo(boolean constructors, boolean methods, boolean fields, String typeReachable,
boolean serialization) {
this.methods = methods;
this.fields = fields;
this.typeReachable = typeReachable;
this.constructors = constructors;
this.weak = weak;
this.serialization = serialization;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageSecurityProviderBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassConditionBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.deployment.logging.LogCleanupFilterBuildItem;
Expand Down Expand Up @@ -411,6 +412,7 @@ public AdditionalBeanBuildItem runtimeConfig() {
@BuildStep
public void withSasl(CombinedIndexBuildItem index,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
BuildProducer<ReflectiveClassConditionBuildItem> reflectiveClassCondition,
BuildProducer<ExtensionSslNativeSupportBuildItem> sslNativeSupport) {

reflectiveClass
Expand All @@ -432,6 +434,10 @@ public void withSasl(CombinedIndexBuildItem index,
for (ClassInfo authenticateCallbackHandler : index.getIndex().getAllKnownImplementors(AUTHENTICATE_CALLBACK_HANDLER)) {
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, authenticateCallbackHandler.name().toString()));
}
// Add a condition for the optional authenticate callback handler
reflectiveClassCondition.produce(new ReflectiveClassConditionBuildItem(
"org.apache.kafka.common.security.oauthbearer.secured.OAuthBearerValidatorCallbackHandler",
"org.jose4j.keys.resolvers.VerificationKeyResolver"));
}

private static void collectImplementors(Set<DotName> set, CombinedIndexBuildItem indexBuildItem, Class<?> cls) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import io.quarkus.deployment.builditem.TransformedClassesBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassConditionBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.deployment.metrics.MetricsCapabilityBuildItem;
Expand All @@ -74,6 +75,8 @@
import io.smallrye.graphql.cdi.config.ConfigKey;
import io.smallrye.graphql.cdi.config.MicroProfileConfig;
import io.smallrye.graphql.cdi.producer.GraphQLProducer;
import io.smallrye.graphql.cdi.tracing.TracingService;
import io.smallrye.graphql.cdi.validation.ValidationService;
import io.smallrye.graphql.schema.Annotations;
import io.smallrye.graphql.schema.SchemaBuilder;
import io.smallrye.graphql.schema.model.Argument;
Expand Down Expand Up @@ -181,13 +184,19 @@ void addDependencies(BuildProducer<IndexDependencyBuildItem> indexDependency) {
}

@BuildStep
void registerNativeImageResources(BuildProducer<ServiceProviderBuildItem> serviceProvider) throws IOException {
void registerNativeImageResources(BuildProducer<ServiceProviderBuildItem> serviceProvider,
BuildProducer<ReflectiveClassConditionBuildItem> reflectiveClassCondition) throws IOException {
// Lookup Service (We use the one from the CDI Module)
serviceProvider.produce(ServiceProviderBuildItem.allProvidersFromClassPath(LookupService.class.getName()));

// Eventing Service (We use the one from the CDI Module)
serviceProvider.produce(ServiceProviderBuildItem.allProvidersFromClassPath(EventingService.class.getName()));

// Add a condition for the optional eventing services
reflectiveClassCondition.produce(new ReflectiveClassConditionBuildItem(TracingService.class, "io.opentracing.Tracer"));
reflectiveClassCondition
.produce(new ReflectiveClassConditionBuildItem(ValidationService.class, "javax.validation.ValidatorFactory"));

// Use MicroProfile Config (We use the one from the CDI Module)
serviceProvider.produce(ServiceProviderBuildItem.allProvidersFromClassPath(MicroProfileConfig.class.getName()));

Expand Down

0 comments on commit 67a776e

Please sign in to comment.