diff --git a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/BarcodeProcessor.java b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/BarcodeProcessor.java new file mode 100644 index 0000000..4483df3 --- /dev/null +++ b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/BarcodeProcessor.java @@ -0,0 +1,69 @@ +package io.quarkiverse.jasperreports.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 and ZXING barcode libraries. + */ +public class BarcodeProcessor extends AbstractJandexProcessor { + + @BuildStep + void indexTransitiveDependencies(BuildProducer index) { + index.produce(new IndexDependencyBuildItem("net.sf.jasperreports", "jasperreports-barcode4j")); + index.produce(new IndexDependencyBuildItem("net.sf.barcode4j", "barcode4j")); + index.produce(new IndexDependencyBuildItem("com.google.zxing", "core")); + } + + @BuildStep + void runtimeBarcodeInitializedClasses(BuildProducer runtimeInitializedPackages) { + //@formatter:off + List classes = new ArrayList<>( + Stream.of(org.krysalis.barcode4j.output.bitmap.BitmapEncoderRegistry.class.getName(), + net.sf.jasperreports.barcode4j.BarcodeUtils.class.getName() + ).toList()); + //@formatter:on + Log.debugf("Barcode4J Runtime: %s", classes); + classes.stream() + .map(RuntimeInitializedPackageBuildItem::new) + .forEach(runtimeInitializedPackages::produce); + } + + @BuildStep + void registerBarcodeForReflection(BuildProducer reflectiveClass, + CombinedIndexBuildItem combinedIndex) { + final List classNames = new ArrayList<>(); + classNames.add("javax.imageio.ImageIO"); + classNames.add(org.krysalis.barcode4j.output.bitmap.ImageIOBitmapEncoder.class.getName()); + classNames.addAll(collectClassesInPackage(combinedIndex, + net.sf.jasperreports.barcode4j.Barcode4JExtensionsRegistryFactory.class.getPackageName())); + + 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 nativeImageResourceProducer, + BuildProducer 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")); + } +} \ No newline at end of file diff --git a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/BatikProcessor.java b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/BatikProcessor.java index 41878c7..439f046 100644 --- a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/BatikProcessor.java +++ b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/BatikProcessor.java @@ -8,6 +8,7 @@ import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.builditem.CombinedIndexBuildItem; import io.quarkus.deployment.builditem.IndexDependencyBuildItem; +import io.quarkus.deployment.builditem.nativeimage.NativeImageResourcePatternsBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedPackageBuildItem; import io.quarkus.logging.Log; @@ -16,8 +17,15 @@ public class BatikProcessor extends AbstractJandexProcessor { @BuildStep void indexTransitiveDependencies(BuildProducer index) { + index.produce(new IndexDependencyBuildItem("org.apache.xmlgraphics", "batik-anim")); + index.produce(new IndexDependencyBuildItem("org.apache.xmlgraphics", "batik-awt-util")); index.produce(new IndexDependencyBuildItem("org.apache.xmlgraphics", "batik-bridge")); + index.produce(new IndexDependencyBuildItem("org.apache.xmlgraphics", "batik-constants")); + index.produce(new IndexDependencyBuildItem("org.apache.xmlgraphics", "batik-css")); + index.produce(new IndexDependencyBuildItem("org.apache.xmlgraphics", "batik-dom")); index.produce(new IndexDependencyBuildItem("org.apache.xmlgraphics", "batik-gvt")); + index.produce(new IndexDependencyBuildItem("org.apache.xmlgraphics", "batik-svg-dom")); + index.produce(new IndexDependencyBuildItem("org.apache.xmlgraphics", "batik-util")); } /** @@ -56,12 +64,22 @@ void runtimeBatikInitializedClasses(BuildProducer reflectiveClass, CombinedIndexBuildItem combinedIndex) { - final List classNames = new ArrayList<>( - collectClassesInPackage(combinedIndex, org.apache.batik.gvt.font.AWTGVTFont.class.getPackageName())); + final List classNames = new ArrayList<>(); + classNames.addAll(collectImplementors(combinedIndex, org.apache.batik.css.parser.ExtendedParser.class.getName())); + classNames.addAll(collectClassesInPackage(combinedIndex, org.apache.batik.gvt.font.AWTGVTFont.class.getPackageName())); Log.debugf("Batik Reflection: %s", classNames); // methods and fields reflectiveClass.produce( ReflectiveClassBuildItem.builder(classNames.toArray(new String[0])).methods().fields().build()); } + + @BuildStep + void registerBatikResources(BuildProducer nativeImageResourcePatterns) { + // Register all message bundles + final NativeImageResourcePatternsBuildItem.Builder builder = NativeImageResourcePatternsBuildItem.builder(); + builder.includeGlob("**/apache/batik/**/resources/**"); + nativeImageResourcePatterns.produce(builder.build()); + } + } \ No newline at end of file diff --git a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/JasperReportsProcessor.java b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/JasperReportsProcessor.java index 25aee5b..3d6223d 100644 --- a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/JasperReportsProcessor.java +++ b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/JasperReportsProcessor.java @@ -107,7 +107,6 @@ void indexTransitiveDependencies(BuildProducer index) index.produce(new IndexDependencyBuildItem("net.sf.jasperreports", "jasperreports")); index.produce(new IndexDependencyBuildItem("net.sf.jasperreports", "jasperreports-data-adapters")); index.produce(new IndexDependencyBuildItem("net.sf.jasperreports", "jasperreports-excel-poi")); - index.produce(new IndexDependencyBuildItem("net.sf.jasperreports", "jasperreports-jaxen")); index.produce(new IndexDependencyBuildItem("net.sf.jasperreports", "jasperreports-jdt")); index.produce(new IndexDependencyBuildItem("net.sf.jasperreports", "jasperreports-json")); index.produce(new IndexDependencyBuildItem("net.sf.jasperreports", "jasperreports-pdf")); @@ -301,10 +300,10 @@ void registerResourceBuildItems(BuildProducer index) { + index.produce(new IndexDependencyBuildItem("net.sf.jasperreports", "jasperreports-jaxen")); index.produce(new IndexDependencyBuildItem("jaxen", "jaxen")); } diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index b4d5401..9a965b4 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -63,6 +63,21 @@ public byte[] text() throws JRException, SQLException { } ---- +== Read-Only Streaming Service + +This extension offers an injectable JasperReports repository capable of managing all the resources required for a report, including referenced sub-reports. Just inject the `ReadOnlyStreamingService` repository and use it with the fill manager to generate the report. + +[source,java] +---- + @Inject + ReadOnlyStreamingService jasperService; + + public JasperPrint fill() throws JRException { + Map params = new HashMap<>(); + return JasperFillManager.getInstance(jasperService.getContext()).fillFromRepo("MyReport.jasper", params); + } +---- + == Native Container @@ -93,22 +108,6 @@ CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] CAUTION: Make sure `.dockerignore` does not exclude `.so` files! -== Read-Only Streaming Service - -A JasperReports repository can handle loading all of the resources a report needs, including any referenced subreports. Simply inject the repository, -then use it with the fill manager to produce the report. - -[source,java] ----- - @Inject - ReadOnlyStreamingService repo; - - public JasperPrint fill() throws JRException { - Map params = new HashMap<>(); - return JasperFillManager.getInstance(repo.getContext()).fillFromRepo("MyReport.jasper", params); - } ----- - [[extension-configuration-reference]] == Extension Configuration Reference diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 4f5eb2e..076c88b 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -175,7 +175,7 @@ true true - --trace-object-instantiation=org.openxmlformats.schemas.wordprocessingml.x2006.main.STZoom$Enum + --trace-object-instantiation=net.sf.jasperreports.engine.component.DefaultComponentsBundle diff --git a/integration-tests/src/main/jasperreports/Barcode4JReport.jrxml b/integration-tests/src/main/jasperreports/Barcode4JReport.jrxml new file mode 100644 index 0000000..cfe762b --- /dev/null +++ b/integration-tests/src/main/jasperreports/Barcode4JReport.jrxml @@ -0,0 +1,136 @@ + +