#Supporting org.apache.xml.security in GraalVM
While working on the European trusted lists feature at $DAY_JOB, we ran into an issue coming from
org.apache.xml.security when running our test suite as a GraalVM native image.
The exception:
java.util.MissingResourceException:
Can't find bundle for base name org/apache/xml/security/resource/xmlsecurity locale en_US
This means the required resource bundle is not available in the generated binary.
So what is happening here? GraalVM builds a native image with a closed-world assumption: it only includes the types it can prove are reachable at build time, and only the resources you explicitly register. Without getting too technical: in code that doesn't rely on reflection, GraalVM is usually smart enough to get this right. But in a big project that loads resources dynamically and uses a lot of reflection, GraalVM sometimes decides a type or resource is unused while it actually is needed, which leads to errors at runtime like the one above.
To fix this, we add the following to the build arguments of the native test executable:
-H:IncludeResourceBundles=org.apache.xml.security.resource.xmlsecurity
When we compile and run the tests again, we hit the next issue:
org.apache.xml.security.signature.XMLSignatureException:
The requested algorithm http://www.w3.org/2000/09/xmldsig#dsa-sha1 does not exist.
Original Message was: org.apache.xml.security.algorithms.implementations.SignatureDSA
Original Exception was java.lang.InstantiationException:
org.apache.xml.security.algorithms.implementations.SignatureDSA
The resource bundle is loaded now, but the signature algorithm implementations are missing. They are instantiated through reflection, so GraalVM left them out of the native binary.
GraalVM lets you declare the types you need for reflection in a reflect-config.json file, which you pass to the
build like this:
-H:ReflectionConfigurationFiles=${basedir}/path/to/reflect-config.json
In that file we list every type GraalVM has to keep in the native binary, for example:
[
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureDSA",
"allDeclaredConstructors": true
}
]
Run the tests again and you get a similar error, this time for ECDSA with SHA-1, so that type needs to be added as well. You're smart readers, so you've probably guessed already that every signature algorithm implementation has to go into the configuration file. On top of that, I found a few other types by trial and error that need to be registered too. The full configuration is at the bottom of this post, ready to copy into your application.
##Making this configuration available for everyone
GraalVM lets library maintainers share these configuration files through the GraalVM Reachability Metadata Repository. That way users of the library don't have to provide the configuration themselves, it's loaded automatically. The next blog post will be about how we get official test support level 1 on the list of GraalVM supported frameworks.
Questions, remarks, comments? Send me an email or ping me on WhatsApp!
Guust
##Full configuration file to get org.apache.xml.security working
[{
"name": "com.sun.org.apache.xpath.internal.functions.FuncNormalizeSpace",
"methods": [
{
"name": "<init>",
"parameterTypes": []
}
]
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA256",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA512",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.c14n.implementations.Canonicalizer20010315ExclOmitComments",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA1",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA384",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSAMD5",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureECDSA",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureDSA",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.c14n.implementations.Canonicalizer20010315OmitComments",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.c14n.implementations.Canonicalizer20010315WithComments",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.c14n.implementations.Canonicalizer20010315ExclWithComments",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA1MGF1",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA224MGF1",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA256MGF1",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA384MGF1",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA512MGF1",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureECDSA$SignatureECDSASHA1",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureECDSA$SignatureECDSASHA224",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureECDSA$SignatureECDSASHA256",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureECDSA$SignatureECDSASHA384",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureECDSA$SignatureECDSASHA512",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureBaseRSA$SignatureRSASHA224",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureHMAC",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureHMAC$SignatureHMACSHA1",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureHMAC$SignatureHMACSHA256",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureHMAC$SignatureHMACSHA384",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.algorithms.implementations.SignatureHMAC$SignatureHMACSHA512",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.transforms.implementations.TransformEnvelopedSignature",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.transforms.implementations.TransformXPath",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.transforms.implementations.TransformBase64",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.transforms.implementations.TransformC14NExclusive",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.transforms.implementations.TransformC14NInclusive",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.encryption.XMLCipher",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.encryption.EncryptedKey",
"allDeclaredConstructors": true
},
{
"name": "org.apache.xml.security.Init",
"allDeclaredConstructors": true
}]
Copyright 2025 Guust Ysebie