Skip to content

Commit

Permalink
Barcode4J native support (#256)
Browse files Browse the repository at this point in the history
  • Loading branch information
melloware authored Oct 19, 2024
1 parent b9e60e5 commit e678a60
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.quarkiverse.primefaces.deployment;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;

import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.logging.Log;

abstract class AbstractJandexProcessor {

protected List<String> collectClassesInPackage(CombinedIndexBuildItem combinedIndex, String packageName) {
final List<String> classes = new ArrayList<>();
final List<DotName> packages = new ArrayList<>(combinedIndex.getIndex().getSubpackages(packageName));
packages.add(DotName.createSimple(packageName));
for (DotName aPackage : packages) {
final List<String> packageClasses = combinedIndex.getIndex()
.getClassesInPackage(aPackage)
.stream()
.map(ClassInfo::toString)
.toList();
classes.addAll(packageClasses);
}
Log.debugf("Package Classes: %s", classes);
return classes;
}

protected List<String> collectInterfacesInPackage(CombinedIndexBuildItem combinedIndex, String packageName) {
final List<String> classes = new ArrayList<>();
final List<DotName> packages = new ArrayList<>(combinedIndex.getIndex().getSubpackages(packageName));
packages.add(DotName.createSimple(packageName));
for (DotName aPackage : packages) {
final List<String> packageClasses = combinedIndex.getIndex()
.getClassesInPackage(aPackage)
.stream()
.filter(ClassInfo::isInterface) // Filter only interfaces
.map(ClassInfo::toString)
.toList();
classes.addAll(packageClasses);
}
Log.debugf("Package Interfaces: %s", classes);
return classes;
}

protected List<String> collectSubclasses(CombinedIndexBuildItem combinedIndex, String className) {
List<String> classes = combinedIndex.getIndex()
.getAllKnownSubclasses(DotName.createSimple(className))
.stream()
.map(ClassInfo::toString)
.collect(Collectors.toList());
classes.add(className);
Log.debugf("Subclasses: %s", classes);
return classes;
}

protected List<String> collectImplementors(CombinedIndexBuildItem combinedIndex, String className) {
Set<String> classes = combinedIndex.getIndex()
.getAllKnownImplementors(DotName.createSimple(className))
.stream()
.map(ClassInfo::toString)
.collect(Collectors.toCollection(HashSet::new));
classes.add(className);
Set<String> subclasses = new HashSet<>();
for (String implementationClass : classes) {
subclasses.addAll(collectSubclasses(combinedIndex, implementationClass));
}
classes.addAll(subclasses);
Log.debugf("Implementors: %s", classes);
return new ArrayList<>(classes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.quarkiverse.primefaces.deployment;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.IndexDependencyBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedPackageBuildItem;
import io.quarkus.logging.Log;

/**
* Register Barcode4J library.
*/
public class Barcode4JProcessor extends AbstractJandexProcessor {

@BuildStep
void indexTransitiveDependencies(BuildProducer<IndexDependencyBuildItem> index) {
index.produce(new IndexDependencyBuildItem("org.primefaces.extensions", "barcode4j-light"));
}

@BuildStep
void runtimeBarcodeInitializedClasses(BuildProducer<RuntimeInitializedPackageBuildItem> runtimeInitializedPackages) {
//@formatter:off
List<String> classes = new ArrayList<>(
Stream.of(org.krysalis.barcode4j.output.bitmap.BitmapEncoderRegistry.class.getName(),
"javax.swing.plaf.metal",
"javax.swing.text.html",
"javax.swing.text.rtf",
"sun.datatransfer",
"sun.swing"
).toList());
//@formatter:on
Log.debugf("Barcode4J Runtime: %s", classes);
classes.stream()
.map(RuntimeInitializedPackageBuildItem::new)
.forEach(runtimeInitializedPackages::produce);
}

@BuildStep
void registerBarcodeForReflection(BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
CombinedIndexBuildItem combinedIndex) {
final List<String> classNames = new ArrayList<>();
classNames.add("javax.imageio.ImageIO");
classNames.add(org.krysalis.barcode4j.output.bitmap.ImageIOBitmapEncoder.class.getName());

Log.debugf("Barcode4J Reflection: %s", classNames);
// methods and fields
reflectiveClass.produce(
ReflectiveClassBuildItem.builder(classNames.toArray(new String[0])).methods().fields().serialization().build());
}

@BuildStep
void registerBarcodeResources(BuildProducer<NativeImageResourceBuildItem> nativeImageResourceProducer,
BuildProducer<NativeImageResourceBundleBuildItem> resourceBundleBuildItem) {
// Register individual resource files
nativeImageResourceProducer.produce(new NativeImageResourceBuildItem(
"org/krysalis/barcode4j/impl/fourstate/usps-4bc-bar-to-character-table.csv"));

// Register resource bundles
resourceBundleBuildItem
.produce(new NativeImageResourceBundleBuildItem("org.krysalis.barcode4j.impl.code128.EAN128AIs"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.primefaces.model.file.CommonsUploadedFile;
import org.primefaces.util.Constants;
Expand All @@ -24,13 +22,11 @@
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
import io.quarkus.logging.Log;
import io.quarkus.primefaces.runtime.PrimeFacesFeature;
import io.quarkus.primefaces.runtime.PrimeFacesRecorder;
import io.quarkus.undertow.deployment.ServletInitParamBuildItem;

class PrimefacesProcessor {
class PrimeFacesProcessor extends AbstractJandexProcessor {

private static final String FEATURE = "primefaces";

Expand All @@ -39,7 +35,7 @@ FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}

@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
@BuildStep
NativeImageFeatureBuildItem nativeImageFeature() {
return new NativeImageFeatureBuildItem(PrimeFacesFeature.class);
}
Expand All @@ -50,7 +46,7 @@ void indexTransitiveDependencies(BuildProducer<IndexDependencyBuildItem> index)
index.produce(new IndexDependencyBuildItem("io.nayuki", "qrcodegen"));
index.produce(new IndexDependencyBuildItem("org.overviewproject", "mime-types"));
index.produce(new IndexDependencyBuildItem("org.primefaces", "primefaces"));
index.produce(new IndexDependencyBuildItem("org.primefaces.extensions", "barcode4j-light"));

index.produce(new IndexDependencyBuildItem("software.xdev", "chartjs-java-model"));
}

Expand Down Expand Up @@ -102,12 +98,6 @@ void substrateResourceBuildItems(BuildProducer<NativeImageResourceBuildItem> nat

// mime types
resourceBundleBuildItem.produce(new NativeImageResourceBundleBuildItem("mime.cache"));

// barcodes
nativeImageResourceProducer.produce(new NativeImageResourceBuildItem(
"org/krysalis/barcode4j/impl/fourstate/usps-4bc-bar-to-character-table.csv"));
resourceBundleBuildItem
.produce(new NativeImageResourceBundleBuildItem("org.krysalis.barcode4j.impl.code128.EAN128AIs"));
}

@BuildStep
Expand Down Expand Up @@ -154,10 +144,6 @@ void registerForReflection(PrimeFacesRecorder recorder, BuildProducer<Reflective
classNames.add(org.primefaces.component.organigram.OrganigramHelper.class.getName());
classNames.addAll(collectImplementors(combinedIndex, PropertyDescriptorResolver.class.getName()));

// Barcode
classNames.add("javax.imageio.ImageIO");
classNames.add(org.krysalis.barcode4j.output.bitmap.ImageIOBitmapEncoder.class.getName());

// Chart XDev models
classNames.addAll(collectClassesInPackage(combinedIndex, "software.xdev.chartjs.model"));

Expand All @@ -167,8 +153,7 @@ void registerForReflection(PrimeFacesRecorder recorder, BuildProducer<Reflective

// method reflection
reflectiveClass.produce(
ReflectiveClassBuildItem.builder(classNames.toArray(new String[0])).methods(true)
.fields(true).build());
ReflectiveClassBuildItem.builder(classNames.toArray(new String[0])).methods().fields().build());

// neither
reflectiveClass.produce(
Expand Down Expand Up @@ -202,41 +187,4 @@ void enforceInitParams(BuildProducer<ServletInitParamBuildItem> initParam) {
// only native uploading is supported no need for Commons FileUpload
initParam.produce(new ServletInitParamBuildItem(Constants.ContextParams.UPLOADER, "native"));
}

public List<String> collectClassesInPackage(CombinedIndexBuildItem combinedIndex, String packageName) {
final List<String> classes = new ArrayList<>();
final List<DotName> packages = new ArrayList<>(combinedIndex.getIndex().getSubpackages(packageName));
packages.add(DotName.createSimple(packageName));
for (DotName aPackage : packages) {
final List<String> packageClasses = combinedIndex.getIndex()
.getClassesInPackage(aPackage)
.stream()
.map(ClassInfo::toString)
.toList();
classes.addAll(packageClasses);
}
Log.debugf("collectClassesInPackage: %s", classes);
return classes;
}

private List<String> collectSubclasses(CombinedIndexBuildItem combinedIndex, String className) {
List<String> classes = combinedIndex.getIndex()
.getAllKnownSubclasses(DotName.createSimple(className))
.stream()
.map(ClassInfo::toString)
.collect(Collectors.toList());
classes.add(className);
return classes;
}

public List<String> collectImplementors(CombinedIndexBuildItem combinedIndex, String className) {
List<String> classes = combinedIndex.getIndex()
.getAllKnownImplementors(DotName.createSimple(className))
.stream()
.map(ClassInfo::toString)
.collect(Collectors.toList());
classes.add(className);
Log.debugf("collectImplementors: %s", classes);
return classes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@

import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeClassInitialization;
import org.krysalis.barcode4j.output.bitmap.BitmapEncoderRegistry;

public class PrimeFacesFeature implements Feature {
private final static String REASON = "PrimeFaces runtime initialization";

@Override
public void afterRegistration(AfterRegistrationAccess access) {
// Barcode component is optional but must register this for native mode since it uses AWT
RuntimeClassInitialization.initializeAtRunTime(BitmapEncoderRegistry.class.getName());
// XDEV Charts.js uses SecureRandom
RuntimeClassInitialization.initializeAtRunTime("software.xdev.chartjs.model.color.Color");
RuntimeClassInitialization.initializeAtRunTime("software.xdev.chartjs.model.color.HSLAColor");
Expand All @@ -19,6 +15,6 @@ public void afterRegistration(AfterRegistrationAccess access) {

@Override
public String getDescription() {
return REASON;
return "PrimeFaces runtime initialization";
}
}
}

0 comments on commit e678a60

Please sign in to comment.