Open Ballsigno opened 2 years ago
Hi @Ballsigno Did you include the test.xsl resource in your native image? https://quarkus.io/guides/writing-native-applications-tips#including-resources
@shumonsharif
Thank you for your reply!
Yes, I have pom.xml that has include setting.
<profile>
~ omit ~
<properties>
<skipITs>false</skipITs>
<quarkus.package.type>native</quarkus.package.type>
<quarkus.native.additional-build-args>-H:IncludeResources=test.xsl</quarkus.native.additional-build-args>
</properties>
Additionally, I have tried this in native mode, and I successfully got the input stream. (But somehow, XSLTInInterceptor doesn't work.)
InputStream testStream = ClassLoaderUtils.getResourceAsStream("test.xsl", this.getClass());
Log.info(testStream.available()); // has value
Likely a bug; thanks for opening the issue! Would you be able to provide a small reproducer?
Alright, I created the small one.
(sorry, I didn't know the message is displayed if I put a link at my push comment.)
I really want to know whether this can be fixed in a few days or not. Let me know if you need anything.
https://github.com/Ballsigno/quarkus-cxf-xslt-test/tree/master/quarkus-cxf-xslt-test
Thank you so much @Ballsigno ! This helps tremendously.
Unfortunately, debugging native issues always takes quite a bit of time. Not sure at this stage if this will be a quick thing or not, though I'm doubtful it'll be fixed and released in a few days. Will certainly prioritize this issue for you, and will keep you posted on progress.
@shumonsharif Thank you for your support! It's understandable. I'm researching whether I can use this for my purpose these days, and now I can see the silver lining. If it turned out to be complicated, I will wait patiently🙏
Making XSLT work in native mode is indeed tricky. Camel Quarkus supports it via its camel-quarkus-xslt
extension. It is tested there only in Camel related scenarios, but I think it might work for you as well. What I think you should do is the following:
quarkus-cxf
version you use. If you wait a week or so, the versions that should work well with each other are Quarkus 2.12.0.Final, Camel Quarkus 2.12.0 (managed in Quarkus Platform BOM 2.12.0.Final, so you actually do not need to care for the Camel Quarkus version) and quarkus-cxf 1.15.0
Starting with 1.15.0, Quarkus CXF will also have a BOM io.quarkiverse.cxf:quarkus-cxf-bom
that you should import into your projectquarkus.camel.xslt.sources
in your application.properties
- see https://camel.apache.org/camel-quarkus/2.11.x/reference/extensions/xslt.htmlThanks for clear steps instructions🙇🏻♂️ I’m not familiar with those things. Therefore I’m not so sure how is that related to my problem. Anyway, I'll give it a try tomorrow or the day after tomorrow.
not so sure how is that related to my problem
To make Java code work in native mode, you need to provide some (sometimes a lot of) GraalVM configuration. That's what Quarkus extensions do (among other things). camel-quarkus-xslt does it for XSLT quite generally, although its main aim is to support Camel integration pipelines using XSLT.
Thank you for your explanation. I tried it Java 11 and 17, but very unfortunately, It didn't work for me. (I created a branch based on the reproducer)
Indeed it seems it affects XSLT feature because the error message is changed. (But my xsl file is valid format.)
java.lang.IllegalArgumentException: Cannot create XSLT template from path: test.xsl
at org.apache.cxf.feature.transform.AbstractXSLTInterceptor.<init>(AbstractXSLTInterceptor.java:74)
at org.apache.cxf.feature.transform.XSLTInInterceptor.<init>(XSLTInInterceptor.java:51)
at org.acme.GreetingResource.test1(GreetingResource.java:47)
at org.acme.GreetingResource$quarkusrestinvoker$test1_7ef637907f0bfe03310c5187ae0e45fdc512a9ab.invoke(Unknown Source)
at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:108)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:140)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:555)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:833)
at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:704)
at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:202)
Caused by: javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet
at org.apache.xalan.xsltc.trax.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:832)
at org.apache.camel.quarkus.support.xalan.XalanTransformerFactory.newTemplates(XalanTransformerFactory.java:70)
at org.apache.cxf.feature.transform.AbstractXSLTInterceptor.<init>(AbstractXSLTInterceptor.java:71)
... 15 more
(add) The real problem is ↓
java.lang.NoClassDefFoundError: org.apache.xalan.xsltc.compiler.ObjectFactory
at org.apache.xalan.xsltc.compiler.ObjectFactory.class$(ObjectFactory.java:292)
at org.apache.xalan.xsltc.compiler.ObjectFactory.findClassLoader(ObjectFactory.java:410)
at org.apache.xalan.xsltc.compiler.Parser.makeInstance(Parser.java:925)
at org.apache.xalan.xsltc.compiler.Parser.startElement(Parser.java:1250)
at org.apache.xalan.xsltc.trax.DOM2SAX.parse(DOM2SAX.java:285)
at org.apache.xalan.xsltc.trax.DOM2SAX.parse(DOM2SAX.java:212)
at org.apache.xalan.xsltc.trax.DOM2SAX.parse(DOM2SAX.java:149)
at org.apache.xalan.xsltc.compiler.Parser.parse(Parser.java:421)
at org.apache.xalan.xsltc.compiler.XSLTC.compile(XSLTC.java:347)
at org.apache.xalan.xsltc.compiler.XSLTC.compile(XSLTC.java:446)
Hmm. I'm totally stuck on this.
Apache Camel seems create a factory and compile a xsl file in initialization process, and XsltBuilder retains the result(template). On the other hand, CXF does similar things after starting application.(When I create XSLTInInterceptor.) I don't know why it doesn't work though. Since there is AbstractPhaseInterceptor, I can create own XSLTinterceptor, but I could not take the template which is created by Apache Camel.
Is there any other way to fix this? I would really appreciate any information.
Finally, I found a workaround! Thank you @ppalaga, I wouldn't have found this approach by myself. I don't know what's going on but, using quarkus camel resources work. I created own interceptor, and avoid a default action that caused the problem.
Instated of doing this...
// AbstractXSLTInterceptor.java
try {
InputStream xsltStream = ClassLoaderUtils.getResourceAsStream(xsltPath, this.getClass());
if (xsltStream == null) {
throw new IllegalArgumentException("Cannot load XSLT from path: " + xsltPath);
}
Document doc = StaxUtils.read(xsltStream);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
try {
transformerFactory.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
} catch (javax.xml.transform.TransformerConfigurationException ex) {
//
}
xsltTemplate = transformerFactory.newTemplates(new DOMSource(doc)); // Somehow failed!!
} catch (TransformerConfigurationException | XMLStreamException e) {
throw new IllegalArgumentException(
String.format("Cannot create XSLT template from path: %s", xsltPath), e);
}
↓
// Inject and pass component as argument from caller.
@Inject
XsltComponent xslt;
// CustomInterceptor
try (XsltEndpoint endPoint = (XsltEndpoint) xslt.createEndpoint("xslt://" + xsltPath)) {
endPoint.init();
xsltTemplate = endPoint.getXslt().getTemplate();
} catch (Exception e) {
throw new IllegalArgumentException(
String.format("Cannot create XSLT template from path: %s", xsltPath), e);
}
@shumonsharif I think I'll close this issue for now. is it okay? (I assume this is low priority...) (I'll be happy if the XSLT feature is officially supported though.)
I think I'll close this issue for now.
I'd vote for keeping this issue open, as it still does not work flawlessly. This issue also contains a lot of useful information (thanks, @Ballsigno !).
I think our general aim should be to have a general purpose Quarkus XSLT extension that could be leveraged for both Camel and CXF use cases. I need to speak with Quarkus team whether they'd be ready to host it within quarkusio/quarkus repo.
According error it mean that we need a ReflectiveClassBuildItem for class org.apache.xalan.xsltc.compiler.ObjectFactory
Basic Info
Hi. I have a question about XSLT feature.
↑ It works fine in dev mode, but when I tried in native mode, it was failed.
If the xsl file doesn't exist, I'm sure I will get 'Cannot load XSLT from path:" error. Therefore I passed the right argument but failed. Is this a bug or am I missing something?