ppalaga commented on issue #4065: URL: https://github.com/apache/camel-quarkus/issues/4065#issuecomment-2429377856
I wrote down this report for OpenJDK. Could you guys please review it before we submit it? ---->8----- Setting translet-name and package-name via TransformerFactory.setAttribute has unexpected effects. ## Background GraalVM native executables do not allow loading classes at runtime due to its closed world assumption. To make XSLT work with them, we generate XSLT Translet classes at build time and let native-image compile them into the native executable. For that to work reliably, we need to be able to set the name of the generated class so that we are then able to find the class and pass it to the native compiler. ## Steps to reproduce To generate a Translet class for a given XSL file, we perform steps similar to the following: ```java import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamSource; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.util.Comparator; public class Main { public static void main(String[] args) throws Exception { TransformerFactory tf = TransformerFactory.newInstance(); tf.setAttribute("generate-translet", true); tf.setAttribute("translet-name", "MyTranslet"); tf.setAttribute("package-name", "org.acme"); tf.setAttribute("destination-directory", "test"); Path test = Path.of("test"); if (Files.exists(test)) { Files.walk(test).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); } File xslFile = new File(args[0]); tf.newTemplates(new StreamSource(Files.newInputStream(xslFile.toPath()))); Files.list(Path.of("test/org/acme")).forEach(System.out::println); } } ``` The reproducer code can be taken from https://github.com/zhfeng/jdk-xalan-issue-reproducer . When this program is compiled through `javac Main.java` and run via `java Main test.xsl`, where `test.xsl` is any simple XSL file, such as ```xml <?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8"/> <xsl:template match="/request"> <xsl:variable name="name" select="//name/text()"/> <response> <message> <xsl:value-of select="concat('Hello, ', $name)"/> </message> </response> </xsl:template> </xsl:stylesheet> ``` then, we *expect* to find the generated translet file under `test/org/acme/MyTranslet.class`. *In reality*, the generated translet is under `test/org/acme/die_verwandlung.class`. ## Analysis The execution flow goes via `com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(Source)`, where a new `com.sun.org.apache.xalan.internal.xsltc.trax.XSLTC` is created and its `setClassName(String)` and `setPackageName(String)` are called. `XSLTC.setClassName(String)` does some sanitization of the passed `className` and if the `_packageName` field is set, it sets the `_className` field to `_packageName + '.' + name`. Because `XSLTC._packageName` is initialized to `"die.verwandlung"`, then, after the first call of `setClassName("MyTranslet")`, the value of `_packageName` is `"die.verwandlung.MyTranslet"`. The `XSLTC.setPackageName("org.acme")` called afterwards, first sets the `_packageName` field to the passed value and then, if `_className != null`, it calls `setClassName(_className)`. In our situation, it effectively means calling `setClassName("die.verwandlung.MyTranslet")`. The sanitization of the passed value done within this second `setClassName()` call transforms `"die.verwandlung.MyTranslet"` into `"die_verwandlung"`. Afterwards, the `_className` field is set to `_packageName + '.' + name` which is `"org.acme" + '.' + "die_verwandlung"` in our case. Observation: the ASF Xalan does not initialize `XSLTC._packageName` to `"die.verwandlung"` and therefore the reproducer code works as expected there. ## Possible solutions A. In `TransformerFactoryImpl.newTemplates(Source)`, call `XSLTC.setPackageName(String)` before `XSLTC.setClassName(String)`. B. In `XSLTC.setPackageName(String)`, instead of calling `setClassName(_className)`, pass only the simple class name extracted from the `_className` field to `setClassName(String)`. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@camel.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org