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
Add known service providers that are not found through module lookup #5985
base: master
Are you sure you want to change the base?
Conversation
Why are these service provides "not found through module lookup"? Do you have an example app that needs this patch or maybe even a test that we could add for this? |
Because the replacement implementation of service loader does not handle services provided inside modules. |
I'm not familiar with that part of the JDK, but can we fix the root cause rather than the symptoms? |
The root cause is not in the JDK. The JDK implementation works fine. The root cause is in the rudimentary replacement implementation of that system in Graal, which only supports services loaded through the class path, but not through the module system. Adding support for that to Graal is a major redesigning task, whereas marking well-known JDK implementations of services is a fast way to make them work. |
I believe adding support for this is better than starting to hard-code service registrations. We'll take another look, support for the module system has significantly been improved over the last couple of months. |
As an intermediate solution this is acceptable. But we should make it high priority to make this change obsolete by implementing proper module-aware serviceProviders lookup in |
I agree.
For reference, the code base I'm working with is GraalVM EE 22.3.1. |
Hi @koutheir
are you sure that the ServiceProviders you are trying to add here are working as expected on JVM? Consider the following example: import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import java.util.ServiceLoader;
public class App {
public static void main(String[] args) throws DatatypeConfigurationException {
DatatypeFactory instance = DatatypeFactory.newInstance();
System.out.println("DatatypeFactory via DatatypeFactory.newInstance():");
System.out.println(instance.getClass().getName());
System.out.println("DatatypeFactory via ServiceLoader.load(DatatypeFactory.class):");
ServiceLoader<DatatypeFactory> serviceLoader = ServiceLoader.load(DatatypeFactory.class);
serviceLoader.forEach(datatypeFactory -> {
System.out.println(datatypeFactory.getClass().getName());
});
}
} if I run this with
As you can see if I instantiate DatatypeFactory via the intended factory method I do get I'm using the same version of GraalVM as the one you reported:
Please provide a reproducer that demonstrates that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #5985 (comment)
Here is a sample ( // Hello.java
// Requires META-INF/services/javax.xml.parsers.DocumentBuilderFactory
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.Set;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
public class Hello extends DocumentBuilderFactory {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory instance = DocumentBuilderFactory.newInstance();
String instanceClassName = instance.getClass().getName();
ServiceLoader<DocumentBuilderFactory> sl = ServiceLoader.load(DocumentBuilderFactory.class);
Set<String> implNames = new HashSet<String>();
Iterator<DocumentBuilderFactory> iter = sl.iterator();
while (iter.hasNext()) {
String implName = iter.next().getClass().getName();
implNames.add(implName);
}
System.out.println(implNames.contains(instanceClassName) ? "PASSED" : "FAILED");
}
@Override
public Object getAttribute(String name) throws IllegalArgumentException {
return null;
}
@Override
public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
return null;
}
@Override
public void setAttribute(String name, Object value) throws IllegalArgumentException {
}
@Override
public void setFeature(String name, boolean value) throws ParserConfigurationException {
}
@Override
public boolean getFeature(String name) throws ParserConfigurationException {
return false;
}
} This sample needs the additional file
Running the sample with JDK 11 produces |
@koutheir your example works perfectly fine with native-image from GraalVM 22.3.1 Java 11 EE:
|
@koutheir I think I know know what is actually going on here. All those failing ServiceLoader related tests install a custom URLClassLoader (see
I can see how this will fail when ran as image. This class of tests performs classloading at image runtime. I will extend my example so that it verifies my assumption. Then I will think about how we could make this working with the help of the agent. |
That is also what my analysis concluded so far. In my sample, I avoided the class loading part though, but that might have hidden the failure somehow. |
This is the working reproducer for the issue.
Currently we are not able to build such code into a working native-image. The changes proposed by this PR are unfortunately not suitable to solve the issue. Maybe with the tracing agent we can track URLClassloader instantiations and their URLs. Then in combination with resource access tracking and predefined classes support we can - maybe - get this working. |
Add known service providers that are not found through module lookup.