-
Notifications
You must be signed in to change notification settings - Fork 1
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
Native Compilation #99
Conversation
@melloware Naive question: would ClassLoader.getResourceAsStream(...) work in native mode? If so, maybe try writing a |
I am not a Jasper expert but this is how you load a .jasper and their underlying code does some magic... mainReport = (JasperReport) JRLoader.loadObject(JRLoader.getLocationInputStream(TEST_REPORT_NAME + ".jasper")); Which does this... public static InputStream getLocationInputStream(String location) throws JRException//FIXME deprecate this?
{
InputStream is = null;
is = getResourceInputStream(location);
if (is == null)
{
is = getFileInputStream(location);
}
if (is == null)
{
is = getURLInputStream(location);
}
return is;
} So that loads the bytes from getResourceAsStream already. |
I wonder if the work I'm doing for #72 would help - by compiling the .jrxml files into .jasper files and adding them as generated resources; just spit-balling here, I would also not consider myself a Jasper expert. |
@nderwin yep i think we have to find a way to add all .jasper compiled into the native image somehow. What makes it tough is the compiled JASPER files have these weird class names like |
Back in my days I used a Maven plugin to compile the .jrxml to a .jasper file (the WAR file only contained the binary). I believe that's the same approach here, we need a build step that takes a .jrxml file and outputs the binary compilation that is included as a native image resource. I don't see a use case requiring native images to support ad-hoc compilation of reports. |
Are you sure it doesn't bring any camel specific classes? Perhaps copying this processor to this project would be a better choice |
I wasn't sure but that is on my list to copy it. That was my gut feeling too to copy it. |
Great minds think alike! 🤝 |
From what I am reading to load Jasper files at runtime in native mode with load bytes we have to do this: https://www.graalvm.org/latest/reference-manual/native-image/metadata/#defining-classes-at-run-time Basically somehow generate this hash config at build time and include it in the deployment. Then when classes are loaded with those identical bytes then GraalVM swaps them in...I think. |
Just a hunch, but shouldn't a |
OK @gastaldi i think i might need to ask the Native experts on Zulip. Here is what I found out....
try {
String jasperFilePath = file.toFile().getAbsolutePath();
JasperReport report = (JasperReport) JRLoader.loadObject(JRLoader.getLocationInputStream(jasperFilePath));
JRReportCompileData reportData = (JRReportCompileData) report.getCompileData();
ReportExpressionEvaluationData mainData = (ReportExpressionEvaluationData) reportData
.getMainDatasetCompileData();
String reportDataClass = mainData.getCompileName();
if (StringUtils.isNotBlank(reportDataClass)) {
byte[] bytes = (byte[]) mainData.getCompileData();
Log.infof("Report Data Class: %s Size: %d", reportDataClass, bytes.length);
additionalClasses.produce(new GeneratedClassBuildItem(false, reportDataClass, bytes));
}
} catch (JRException e) {
Log.error("Error loading report file class.", e);
}
So I loaded the right class and bytes in Native mode.
|
@zakkak any hints here? |
I made progress here. Stuck on the next issue but got a lot further. |
b1f9183
to
eb89d88
Compare
@melloware Are you seeing |
Not yet you are still working on that. I am loading the Jasper files I stored in sec main resources right now for my testing. I think I will have this all working tomorrow! |
I need to have a better look (and possibly reproduce the issue) to give better feedback but so far I can say the following:
|
I got it working @zakkak i look through all the jasper file and pull out the bytecode and load it with Genrated BuildIten. Then I GraalVM substituted the JRClassloader the method that takes bytes and load the class forName since I know I have already preloaded it. So far it's all working. |
Great work @melloware! |
@gastaldi Holy sh$%t i got it all working and tests passing in Native Mode! |
deployment/src/main/java/io/quarkiverse/jasperreports/deployment/SaxonProcessor.java
Show resolved
Hide resolved
I am going to commit this so i can continue working on new PR's with this baseline since it all works. @gastaldi we can always refactor later. |
Fix #94
Fix #22
OK made a ton of progress to the point where I could load the native image and run
http://localhost:8080/jasperreports/csv
and get an error.A few things.
In Native mode you can't compile JRXML because there is not Java available "no Javac found to compile JRXML". However if you add Java to the native image you still get errors because of the dynamic nature of Compilation so you can't use JRXML in native you have to use
.jasper
compiled files which is Jasper's recommendation anyway.I found Camel Xalan support and added it. I don't love adding this but they already have Xalan Native stuff in Camel. https://github.com/apache/camel-quarkus/blob/main/extensions-support/xalan/deployment/src/main/java/org/apache/camel/quarkus/support/xalan/deployment/XalanNativeImageProcessor.java
Now the real problem when loading a
.jasper
compiled file is this...Jasper uses the classloader to load the
.jasper
file which is ByteCode which is NOT allowed in GraalVMcom.oracle.svm.core.jdk.UnsupportedFeatureError: No classes have been predefined during the image build to load from bytecodes at runtime.
. @gastaldi i don't know if there is a clever way to tell GraalVM to load the.jasper
files?