Bug #5920
closedJava reflexive API fails to run, throws ClassNotFoundException for org.jdom2.Document
100%
Description
With Saxon 12 (EE) but not with Saxon 11 importing a module that references a Java method using reflection does not run but fails with the stack below. I've pared it down: simply having the reference to the Java methods seems to be enough.
Run as: java -cp saxon-ee-12.0.jar net.sf.saxon.Query -q:crash.xqy
xception in thread "main" java.lang.NoClassDefFoundError: org/jdom2/Document at net.sf.saxon.option.jdom2.JDOM2ObjectModel.isRecognizedNodeClass(JDOM2ObjectModel.java:159) at net.sf.saxon.option.jdom2.JDOM2ObjectModel.getPJConverter(JDOM2ObjectModel.java:104) at net.sf.saxon.expr.PJConverter.allocate(PJConverter.java:220) at com.saxonica.expr.JavaExtensionFunctionCall.typeCheck(JavaExtensionFunctionCall.java:228) at com.saxonica.config.JavaExtensionLibrary$UnresolvedExtensionFunctionCall.typeCheck(JavaExtensionLibrary.java:1164) at net.sf.saxon.expr.Operand.typeCheck(Operand.java:224) at net.sf.saxon.expr.flwor.FLWORExpression.lambda$typeCheck$1(FLWORExpression.java:178) at net.sf.saxon.expr.flwor.LetClause.processOperands(LetClause.java:133) at net.sf.saxon.expr.flwor.FLWORExpression.typeCheck(FLWORExpression.java:180) at net.sf.saxon.query.XQueryFunction.compile(XQueryFunction.java:423) at net.sf.saxon.query.XQueryFunctionLibrary.fixupGlobalFunctions(XQueryFunctionLibrary.java:423) at net.sf.saxon.query.QueryModule.fixupGlobalFunctions(QueryModule.java:1103) at net.sf.saxon.expr.instruct.Executable.fixupQueryModules(Executable.java:446) at net.sf.saxon.query.XQueryParser.makeXQueryExpression(XQueryParser.java:175) at net.sf.saxon.query.StaticQueryContext.compileQuery(StaticQueryContext.java:563) at net.sf.saxon.query.StaticQueryContext.compileQuery(StaticQueryContext.java:625) at net.sf.saxon.s9api.XQueryCompiler.compile(XQueryCompiler.java:651) at net.sf.saxon.Query.compileQuery(Query.java:869) at net.sf.saxon.Query.doQuery(Query.java:330) at net.sf.saxon.Query.main(Query.java:106) Caused by: java.lang.ClassNotFoundException: org.jdom2.Document at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
Files
Updated by Martin Honnen over 1 year ago
Oh no, 12.1 delayed further with that finding...?
Updated by Martin Honnen over 1 year ago
I tried to put the JDOM 2 jar on the class path with e.g. java -cp 'C:\Program Files\Saxonica\SaxonEE12-0J\saxon-ee-12.0.jar;jdom2-2.0.6.jar' net.sf.saxon.Query -q:crash.xqy
, now Saxon 12 complains about missing dom4j
Exception in thread "main" java.lang.NoClassDefFoundError: org/dom4j/Document
at net.sf.saxon.option.dom4j.DOM4JObjectModel.isRecognizedNodeClass(DOM4JObjectModel.java:161)
at net.sf.saxon.option.dom4j.DOM4JObjectModel.getPJConverter(DOM4JObjectModel.java:88)
at net.sf.saxon.expr.PJConverter.allocate(PJConverter.java:220)
at com.saxonica.expr.JavaExtensionFunctionCall.typeCheck(JavaExtensionFunctionCall.java:228)
at com.saxonica.config.JavaExtensionLibrary$UnresolvedExtensionFunctionCall.typeCheck(JavaExtensionLibrary.java:1164)
at net.sf.saxon.expr.Operand.typeCheck(Operand.java:224)
at net.sf.saxon.expr.flwor.FLWORExpression.lambda$typeCheck$1(FLWORExpression.java:178)
at net.sf.saxon.expr.flwor.LetClause.processOperands(LetClause.java:133)
at net.sf.saxon.expr.flwor.FLWORExpression.typeCheck(FLWORExpression.java:180)
at net.sf.saxon.query.XQueryFunction.compile(XQueryFunction.java:423)
at net.sf.saxon.query.XQueryFunctionLibrary.fixupGlobalFunctions(XQueryFunctionLibrary.java:423)
at net.sf.saxon.query.QueryModule.fixupGlobalFunctions(QueryModule.java:1103)
at net.sf.saxon.expr.instruct.Executable.fixupQueryModules(Executable.java:446)
at net.sf.saxon.query.XQueryParser.makeXQueryExpression(XQueryParser.java:175)
at net.sf.saxon.query.StaticQueryContext.compileQuery(StaticQueryContext.java:563)
at net.sf.saxon.query.StaticQueryContext.compileQuery(StaticQueryContext.java:625)
at net.sf.saxon.s9api.XQueryCompiler.compile(XQueryCompiler.java:651)
at net.sf.saxon.Query.compileQuery(Query.java:869)
at net.sf.saxon.Query.doQuery(Query.java:330)
at net.sf.saxon.Query.main(Query.java:106)
Caused by: java.lang.ClassNotFoundException: org.dom4j.Document
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 20 more
Updated by Norm Tovey-Walsh over 1 year ago
Hi Mary,
I can't explain off the top of my head why we're trying to instantiate these other object models in this case, but as a quick workaround, adding jdom2 and dom4j jar files to the class path seems to avoid the NoClassDefFound
error(s).
Updated by Norm Tovey-Walsh over 1 year ago
This is a direct consequence of the fix for #5725 which observes that it's a risky change.
We no longer attempt to check if models (.e.g, jdom2 and dom4j) are available before registering them as external models, so they get registered.
But then, when we're attempting to reflexively instantiate a Java class, we attempt to get a converter for those models, they aren't available, and a NoClassDefError
is thrown.
I'm assuming that it's still desirable not to attempt to instantiate them every time (the #5725 fix), so I'm moving the try/catch into the PJConverter
and JPConverter
classes. This means attempting to instantiate, for example, a java.io.File
will succeed even though (some) of the models may fail to instantiate.
I wonder if it's worth adding an API on Configuration
to mark some registered models as unavailable. If we don't then we're going to try (and fail, and throw an exception) on every attempt to instantiate a Java class reflexively. That seems like a potential problem if there are stylesheets out there that instantiate a lot of objects.
Updated by Michael Kay over 1 year ago
Yes, I think catching the exception in PJConverter and JPConverter is the way to do it. I've been hunting around to see if there's any way we can detect the availability of the classes without throwing the exception and I think the answer is no. I've arranged it so that if the exception is thrown the first time, then the object model is deregistered from the configuration, which means no further attempts will be made.
I added a unit test to jaxptest/ExtensionTest that registers a user-defined ExternalObjectModel and demonstrates recovery when it's found that it can't be loaded.
Updated by Norm Tovey-Walsh over 1 year ago
Ah. Okay. I'll check your commits and discard mine. (I'd fixed the bug! ;-), I was just trying to decide if pulling the failed models out of the external model list was the right way forward.)
Updated by Michael Kay over 1 year ago
- Category set to Saxon extensions
- Status changed from New to Resolved
- Assignee set to Michael Kay
- Priority changed from Low to Normal
- Applies to branch trunk added
- Fix Committed on Branch 12, trunk added
- Platforms Java added
Fixed on the 12.x and main branches.
Updated by O'Neil Delpratt over 1 year ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Fixed in Maintenance Release 12.1 added
Bug fix applied in the Saxon 12.1 maintenance release.
Please register to edit this issue