Skip to content
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

java.lang.IllegalAccessError: no such constructor: org.eclipse.wst.xml.xpath2.processor.DefaultDynamicContext.<init>(XSModel,Document)void/newInvokeSpecial #655

Open
martin-honnen opened this issue Jan 28, 2025 · 10 comments

Comments

@martin-honnen
Copy link

I am trying to the lastet IKVM/IKVM.Maven release with .NET 8 to use the Apache Java Xerces library with XSD 1.1. support.

However, I can't use the XSD 1.1 features depending on the used XPath 2 library as under IKVM I get an error java.lang.IllegalAccessError: no such constructor: org.eclipse.wst.xml.xpath2.processor.DefaultDynamicContext.<init>(XSModel,Document)void/newInvokeSpecial.

Complete stack is below, sample project is at https://github.com/martin-honnen/Xsd11IkvmTest1.

Any hints appreciated on how to resolve this.

  Nachricht = no such constructor: org.eclipse.wst.xml.xpath2.processor.DefaultDynamicContext.<init>(XSModel,Document)void/newInvokeSpecial
  Quelle = IKVM.Java
  Stapelüberwachung:
   bei java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(Class callerClass, Int32 refKind, Class defc, String name, Object type)
   bei IKVM.Runtime.ByteCodeHelper.DynamicLoadMethodHandleImpl(Int32 kind, String clazz, String name, String sig, CallerID callerID)
   bei IKVM.Runtime.ByteCodeHelper.DynamicBinderMemberLookup[T](Int32 kind, String clazz, String name, String sig, CallerID callerID)
   bei org.apache.xerces.impl.xs.AbstractXPath2EngineImpl.__<>MHC(XSModel , Document )
   bei org.apache.xerces.impl.xs.AbstractXPath2EngineImpl.initXPath2DynamicContext(XSModel xsm, Document d, Map m)
   bei org.apache.xerces.impl.xs.XMLAssertXPath2EngineImpl.initXPathProcessor()
   bei org.apache.xerces.impl.xs.XMLAssertXPath2EngineImpl.startElement(QName qn, XMLAttributes xmla, Augmentations a)
   bei org.apache.xerces.impl.xs.XSDAssertionValidator.handleStartElement(QName qn, XMLAttributes xmla)
   bei org.apache.xerces.impl.xs.XMLSchemaValidator.assertionValidatorStartElementDelegate(QName qn, XMLAttributes xmla, Augmentations a)
   bei org.apache.xerces.impl.xs.XMLSchemaValidator.handleStartElement(QName qn, XMLAttributes xmla, Augmentations a)
   bei org.apache.xerces.impl.xs.XMLSchemaValidator.startElement(QName qn, XMLAttributes xmla, Augmentations a)
   bei org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement()
   bei org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.FragmentContentDispatcher.dispatch(Boolean b)
   bei org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Boolean b)
   bei org.apache.xerces.parsers.XML11Configuration.parse(Boolean b)
   bei org.apache.xerces.parsers.XML11Configuration.parse(XMLInputSource xmlis)
   bei org.apache.xerces.jaxp.validation.StreamValidatorHelper.validate(Source s, Result r)
   bei org.apache.xerces.jaxp.validation.ValidatorImpl.validate(Source s, Result r)
   bei javax.xml.validation.Validator.validate(Source source)
   bei Xsd11IkvmTest1.Program.ValidationXmlAgainstXsd(String xmlFile, String xsdFile, SchemaFactory schemaFactory) in C:\Users\marti\source\repos\Xsd11IkvmTest1\Program.cs: Zeile70
   bei Xsd11IkvmTest1.Program.ValidateXmlAgainstXsd11(String xmlFile, String xsdFile) in C:\Users\marti\source\repos\Xsd11IkvmTest1\Program.cs: Zeile35
   bei Xsd11IkvmTest1.Program.Main(String[] args) in C:\Users\marti\source\repos\Xsd11IkvmTest1\Program.cs: Zeile20

@AliveDevil
Copy link
Collaborator

ikvmc changes the constructor to

	[LineNumberTable(new byte[]
	{
		159, 124, 161, 83, 234, 51, 236, 79, 104, 117,
		108
	})]
	public DefaultDynamicContext(object schema, Document doc)

Probably an error with the Maven type resolution, as in it doesn't find the XSModel.

Source for DefaultDynamicContext: https://github.com/xercesj/xpath20/blob/master/webtools.sourceediting.xpath/bundles/org.eclipse.wst.xml.xpath2.processor/src/org/eclipse/wst/xml/xpath2/processor/DefaultDynamicContext.java

@AliveDevil
Copy link
Collaborator

Btw, adding

ikvm.runtime.Startup.addBootClassPathAssembly(Assembly.Load("xercesImpl"));

Fixes the startup error.

@wasabii
Copy link
Contributor

wasabii commented Jan 28, 2025

I think the problem is a string not being interned. I'm doing a deep dive.

@wasabii
Copy link
Contributor

wasabii commented Jan 28, 2025

So, here's what's happening as I understand it so far.

The primary package: com.evolvedbinary.thirdparty.org.eclipse.wst.xml:xpath2 produces xpath2.dll. The JAR file of xpath2.jar references classes which only exist in xercesImpl.jar. However, the Maven package for the first does NOT have a reference to the second. Hence why you had to put both MavenReferences in the csproj. They didn't automatically depend on each other. Because the dependencies are missing.

But just putting them both in the csproj doesn't cause the compiler to actually consider them as depending on each other. So, xpath2 is compiled without reference to xercesImpl. Viewing the logs for that we see:

DEBUG: Executing D:\packages\NuGet\cache\ikvm.msbuild.tools.runtime.win-x64\8.10.3\ikvmc\net8.0\win-x64\ikvmc.exe @D:\source\Xsd11IkvmTest1\obj\Debug\net8.0\ikvm\stage\1\c6cd8a609b4b912405b5044bd1868df5\xpath2.dll.rsp
ERROR: warning IKVMC0100: Class "org.eclipse.core.runtime.Plugin" not found
ERROR: warning IKVMC0100: Class "java_cup.runtime.lr_parser" not found
ERROR: warning IKVMC0100: Class "java_cup.runtime.Scanner" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.XSTypeDefinition" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.XSComplexTypeDefinition" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.XSSimpleTypeDefinition" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.ShortList" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.XSObjectList" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.impl.dv.XSSimpleType" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.dom.PSVIElementNSImpl" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.util.XMLChar" not found
ERROR: warning IKVMC0100: Class "com.ibm.icu.lang.UCharacter" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.impl.dv.util.Base64" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.impl.dv.util.HexBin" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.dom.PSVIAttrNSImpl" not found
ERROR: warning IKVMC0100: Class "com.ibm.icu.text.Normalizer" not found
ERROR: warning IKVMC0100: Class "com.ibm.icu.text.Normalizer$Mode" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.XSModel" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.XSElementDeclaration" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.XSAttributeDeclaration" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.ItemPSVI" not found
ERROR: warning IKVMC0100: Class "com.ibm.icu.text.UTF16" not found
ERROR: warning IKVMC0100: Class "java_cup.runtime.Symbol" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.util.XML11Char" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.impl.dv.ValidatedInfo" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.impl.validation.ValidationState" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.impl.dv.xs.TypeValidatorHelper" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.impl.dv.InvalidDatatypeValueException" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.AttributePSVI" not found
ERROR: warning IKVMC0100: Class "org.apache.xerces.xs.ElementPSVI" not found

So, a bunch of errors because the classes are missing, because the reference was not added at compile time.

These errors are not fatal. What happens is IKVM, insert of failing, defaults to dynamic dispatch for these missing types in the xpath2 assembly. What this means is any method that would accept these classes, or any reference to these classes, are replaced by System.Object. So, the ctor that is missing is in this situation. The ctor was legit not created with the expected signature. Instead, the first argument it accepts is System.Object.

When resolving the constructor, then, the dynamic lookup goes through RuntimeJavaType.GetMethodWrapper. That scans the methods for matching names and signatures. It looks like the original signature is coming through correctly. But the code isn't matching it:


	internal RuntimeJavaMethod GetMethodWrapper(string name, string sig, bool inherit)
	{
		RuntimeJavaMethod[] array = GetMethods();
		string text = string.IsInterned(name);
		string text2 = string.IsInterned(sig);
		RuntimeJavaMethod[] array2 = array;
		foreach (RuntimeJavaMethod runtimeJavaMethod in array2)
		{
			if ((object)runtimeJavaMethod.Name == text && (object)runtimeJavaMethod.Signature == text2)
			{
				return runtimeJavaMethod;
			}
		}
		RuntimeJavaType baseTypeWrapper = BaseTypeWrapper;
		if (inherit && baseTypeWrapper != null)
		{
			return baseTypeWrapper.GetMethodWrapper(name, sig, inherit);
		}
		return null;
	}

That loop isn't finding it. But the values seem correct. So I think because it's doing a reference compare one side isn't interned.

@martin-honnen
Copy link
Author

Btw, adding

ikvm.runtime.Startup.addBootClassPathAssembly(Assembly.Load("xercesImpl"));

Fixes the startup error.

Many thanks @AliveDevil , good to know.

@wasabii
Copy link
Contributor

wasabii commented Jan 28, 2025

That fixed it? For real?

@martin-honnen
Copy link
Author

That at least allows me to run the code to perform the XSD 1.1 validation using XPath 2 in assertions, of course I would prefer not to have to use the explicit loading with ikvm.runtime.Startup.addBootClassPathAssembly(Assembly.Load("xercesImpl")); or the other two calls.

@wasabii
Copy link
Contributor

wasabii commented Jan 28, 2025

Okay. I see. I was misled by the debugger. Test was working. This comes down to the code in sun.invoke.util.VerifyAccess. A method I don't quite fully understand yet.

Part of which is overridden by map.xml to return null for the class loader of the second type if and only if it appears in the bootstrap class loader. I don't understand the point of this yet.

@martin-honnen
Copy link
Author

The primary package: com.evolvedbinary.thirdparty.org.eclipse.wst.xml:xpath2 produces xpath2.dll. The JAR file of xpath2.jar references classes which only exist in xercesImpl.jar. However, the Maven package for the first does NOT have a reference to the second. Hence why you had to put both MavenReferences in the csproj. They didn't automatically depend on each other. Because the dependencies are missing.

But just putting them both in the csproj doesn't cause the compiler to actually consider them as depending on each other. So, xpath2 is compiled without reference to xercesImpl.

I have contacted the guy that produces these com.evolvedbinary.thirdparty packages whether he could add the missing dependencies. But according to him

The problem being that Maven does not permit cyclic dependencies (at least at compile time, I am not sure about runtime???). Yet, I see that:
com.evolvedbinary.thirdparty.xerces:xercesImpl:2.12.2.1:xml-schema-1.1 requires at runtime (possibly also at compile time????): com.evolvedbinary.thirdparty.org.eclipse.wst.xml:xpath2:1.2.1
com.evolvedbinary.thirdparty.org.eclipse.wst.xml:xpath2:1.2.1 requires com.evolvedbinary.thirdparty.xerces:xercesImpl:2.12.2.1 at compile time.

I don't have much experience with creating Maven/POM files and dependencies, I mainly consume them; @wasabii, what's your opinion on this case, can the cyclic interdependencies between xercesImpl and xpath2 be cleanly specified on Maven to cater for both Maven rules as well as to allow IKVM.Maven to find and collect and load all assemblies without having to resort to explicit ikvm.runtime.Startup.addBootClassPathAssembly calls?

@wasabii
Copy link
Contributor

wasabii commented Feb 4, 2025

No, Maven does not support cyclic dependencies. So the classes on one side or the other, whichever that may work out to be, end up using dynamic dispatch to the other.

I do believe though that since these are generated by IKVM.Maven.Sdk, and IKVM.Maven.Sdk uses the AppDomainAssemblyClassLoader by default, you don't have to call ikvm.runtime.Startup.addBootClassPathAssembly. It should be sufficient to just load it in .NET. Assembly.Load, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants