'quarkus native reflection configuration for whole package
I'm building quarkus native and using Stripe sdk as external library. In order to support Stripe sdk it I needed to create reflection-config.json file and set in the application.properties quarkus.native.additional-build-args=-H:ReflectionConfigurationFiles=reflection-config.json
The reflection-config.json looks like so:
{
"name": "com.stripe.model.Customer",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "com.stripe.model.Customer$InvoiceSettings",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "com.stripe.model.StripeError",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "com.stripe.model.PaymentIntent",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "com.stripe.model.PaymentMethod",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
}....
and so on. It contains too many classes. My question is if there is a way to set the whole package instead of tons of classes? For example:
{
"name": "com.stripe.model.*",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
}
Didn't find any mention for it.
Solution 1:[1]
You can do that with a Quarkus extension, get classes from the index and produce a ReflectiveClassBuildItem for all classes matching the package.
It's not that hard but requires a bit of work.
A less verbose alternative to what you're doing is to use @RegisterForReflection(targets = { ... }).
That's the only alternatives right now.
Solution 2:[2]
The cleanest solution seems to be writing a Quarkus extension.
Or, if you don't want to list RegisterForReflection targets manually, another possibility is to have reflection-config.json generated externally (probably using annotation processor? or maven/gradle task).
Solution 3:[3]
See update below.
I'm having the exact same use case to programmatically add all classes of a package for reflection without writing an extension.
My goal is to add jOOQ generated DB classes for reflection so I can use them in a native compiled Quarkus GraalVM image with RESTEasy Reactive Jackson.
As there are a lot of these classes I don't really want to manually populate the reflection-config.json or the targets with a @RegisterForReflection annotation on a empty class.
I'm using Quarkus 2.7.0.Final (not io.quarkus.platform as it is not released yet) with Gradle 7.3.3 and tried the following, which unfortunately does not work.
But I guess this only works when building extensions ?
package com.example.restapi.graal;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.IndexView;
public class JooqReflectionProcessor {
private static final String JOOQ_DB_REFLECT_CLASSES = "com\\.example\\.restapi\\.db\\..+\\.tables\\.(pojos|records)\\..+";
@BuildStep
public void build(BuildProducer<ReflectiveClassBuildItem> reflectiveClass, CombinedIndexBuildItem indexBuildItem) {
IndexView index = indexBuildItem.getIndex();
for (ClassInfo clazz : index.getKnownClasses()) {
if (clazz.name().toString().matches(JOOQ_DB_REFLECT_CLASSES)) {
reflectiveClass.produce(new ReflectiveClassBuildItem(true, true, clazz.name().toString()));
}
}
}
}
Update:
It ain't pretty but I ended up writing a Gradle task which automatically creates the desired jOOQ reflection class with the @RegisterForReflection(targets = {...}) annotation:
task writeJooqReflectionClass {
DefaultSourceDirectorySet sourceSet = project.sourceSets.findByName('main').java
File jooqSrcDir = sourceSet.srcDirs
.stream()
.filter { it.path.replace('\\', '/').matches('.+src/generated/jooq/main') }
.findFirst()
.get()
ArrayList<String> classesForReflection = sourceSet
.filter {
it.path.contains(jooqSrcDir.path) &&
it.path.replace('\\', '/').matches('.+tables/(pojos|records)/.+') &&
it.path.endsWith('.java')
}
.collect { it.path.replaceAll('[\\\\|/]', '.').substring(jooqSrcDir.path.length() + 1).replace('.java', '.class') }
Collections.sort(classesForReflection)
File file = new File("${jooqSrcDir.path}/com/example/restapi/db", "JooqReflectionConfig.java")
file.getParentFile().mkdirs()
file.text = """\
package com.example.restapi.db;
import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection(targets = {
${String.join(',\n ', classesForReflection)}
})
public class JooqReflectionConfig {
}
""".stripIndent()
}
compileJava.dependsOn(writeJooqReflectionClass)
For example produces Class com.example.restapi.db.JooqReflectionConfig with content:
package com.example.restapi.db;
import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection(targets = {
com.example.restapi.db.master.tables.pojos.TableA.class,
com.example.restapi.db.master.tables.pojos.TableB.class,
com.example.restapi.db.master.tables.records.TableA.class,
com.example.restapi.db.master.tables.records.TableB.class,
com.example.restapi.db.mdc.tables.pojos.TableC.class,
com.example.restapi.db.mdc.tables.pojos.TableD.class,
com.example.restapi.db.mdc.tables.records.TableC.class,
com.example.restapi.db.mdc.tables.records.TableD.class
})
public class JooqReflectionConfig {
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Guillaume Smet |
| Solution 2 | Salvian Reynaldi |
| Solution 3 |
