ServiceLoader cannot find service loaded from path - java

I have been trying to do a kind of plugin-system using the ServiceLoader. There are 2 modules, the first provides the abstract class LoadedRealmPlugin. The second one extends this class. I have added the file corresponding to the full name of the ServiceProvider and added the service-class to it. IntelliJ does not find any errors (but when changing the filename or classname it does). Here is the structure:
MainModule
src
main
java
com.interestingcompany.mainmodule
LoadedRealmPlugin
MainModule.iml
Plugin
META-INF
services
com.interestingcompany.mainmodule (-> Content: "PluginExtension")
src
PluginExtension
Plugin.iml
(This is simplified, I left out classes that (I think) are not important to the ServiceLoader. I can post a screenshot of the actual structure if anyone needs it)
Here is the code I use to load the Service:
File file = new File("Plugins/Plugin.jar");
URLClassLoader c = new URLClassLoader(new URL[]{file.getAbsoluteFile().toURI().toURL()});
ServiceLoader<LoadedRealmPlugin> loader = ServiceLoader.load(LoadedRealmPlugin.class, c);
LoadedRealmPlugin p = loader.iterator().next(); // Throws a java.util.NoSuchElementException
p.Initialize(RealmPath); // Abstract method implemented in the service
return p;
When trying to run it, I always get an empty ServiceLoader. I looked at this post, but I was not quite sure about how to apply that answer since I am trying to load my plugin from a file. In addition, I found this post. Yet, there was no answer, just some comments that did not seem to have answered the question.
As you might have been able to tell, this is my first time working with classloaders. If there is any additional information needed, just ask me. Thank you for reading through my beginner troubles.

package-less classes are in the unnamed package, which is inaccessible to rather a lot of code, notably including here.
Put PluginExtension.java in a package, make sure the content of your META-INF/services/com.ic.mainmodule file reflects this (content should be pkg.PluginExtension), and it'll work fine.

Related

Tomcat webclassloader fails to find a class

In a Tomcat 7 I have a pretty standar jar file on WEB-INF/lib. Inside this jar I have this class called Parser, and next to it (on the same dir) I have another one called AutomaticLocalLoader. Compilation gives no problem at all. In run time the AutomaticLoader class is found, and when It needs the Parser class, I get a NoClassDefFoundError
The Parser and AutomaticLoader class have been working without this problem for 15 years!! in many diferent vers of java and tomact; and now out of the blue, I am getting this NoClassDefFoundError, only for the Parser class. I already put a copy on a directory inside the WEB-INF/classes path and still got the same error. I already created my own ClassLoader to see if I get some error loading the class from the WEB-INF/classes directory by myself, but I can load it without problems.
log.info("Leer " + aFlInstructions[i].getAbsolutePath());
LoaderTest A = new LoaderTest();
A.test("com.hds.resolve.model.aguila.AutomaticLocalLoader");
LoaderTest B = new LoaderTest();
B.test("com.hds.resolve.model.aguila.Parser");
if(!bOverrideInputDir)
Psr = new Parser(aFlInstructions[i]);
else
Psr = new Parser(aFlInstructions[i], new String[] { StrLocalDirectory } );
The LoaderTest class, try to create the Class Object for the given name using Class.forName. If NoClassDefFoundError, then try to load the class using my own classloader and then create the class.
For the AutomaticLoader, it succed at the first try. For the Parser class if fails, then successfully load it with the custom classloader. Of course when the code reach the "new Parser" part, the old webclassloader still fails and throws the NoClassDefFoundError.
Both Parser and AutomaticLocalLoader belong to the same package and are stored on the same jar inside WEB-LIB.
Funny enough, the error does always happen on production... but never in my machine. I do not use customs classloaders except for doing this debug. Also, trying an old version of the software seems to fix the error. No idea why.
I think I can hack a solution messing with the tomcat's webclassloader, but I really would prefer to understand what is going wrong with this code.

File path (JAVA EE)

I'm working in a web project and I'm having troubles with files(java.io.File). The problem is only when I run as web application(tomcat 7), if I run as Java Application, the problem doesn't exist.
When I instantiate a file, new File("dir");, its path become C://Windows/System32/dir, this way, i can't do anything, maybe cause don't have Windows privilegies.
"I solved the problem" passing new File("C://Users/user/dir"), but I don't like this solution. I wanted to do this automatically, get the app path, for example. I'm coding in my machine, and after the deploy.... i don't know.
Any tips?
That's the part of the project that I'm having the problem, a jsf bean. My view calls the method addFile() to save the file that I receive from my view. It's working, but i have to pass the path like I said before, like is on the code below. The path goes to the Windows dir System32
Bean.java
#ManagedBean
#ViewScoped
public class Bean {
//ATTRIBUTES AND METHODS
public void addFile() {
File temporaryFile = new File("temporary");
//...
//...
//...
}
}
Sorry for my english, i'm brazillian.
There is a method in the File class that does exactly what you're looking for: https://docs.oracle.com/javase/8/docs/api/java/io/File.html#createTempFile-java.lang.String-java.lang.String-
Alternatively you can assemble the file's path yourself:
File myTempFile = new File(System.getProperty("java.io.tmpdir"),"temporary");
you can add folder resources in web folder then add files as you want
i tested it from adding some styles (css) and javascript and call them in jsf page.as example if you create file named x in folder files under web/resources folder
new File("files/x");
wishing the answer helps you .you can tell me if any problem happens again

Using external java library in KNIME. Why initialization of one class fails while it succeeds for another class?

I have a problem integrating Java code into KNIME. Similar posts on Knime forum (http://tech.knime.org/forum/knime-general/using-external-jar-in-java-snippet-node-workflow-not-able-to-initialize-class-of) were of little help and I also posted a question there but have not got answer so far, so I'm trying my luck here.
I am trying to integrate my code into KNIME workflow using JavaSnippet. I have exported the code into a jar and put it into the KNIME jre/lib/endorsed folder. The code references CDK 1.4.19 and I have also placed the corresponding jar file into the same directory. I do not have CDK node extensions installed in KNIME and using them is also not an option in my case.
The code starts with:
IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
SmilesParser sp= new SmilesParser(builder);
When I try to execute JavaSnippet I get the following exception message:
Evaluation of java snippet failed for row "Row0". Exception message: Could not initialize class org.openscience.cdk.smiles.SmilesParser
When I just try
IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
It works and I get no exception message. I have checked, the builder is not a null. However, when I try to initialize SmilesParser, it fails. This class is public. It has no default constructor and has one public constructor that takes IChemObjectBuilder as a parameter.
I have tried to use class loader:
URL[] classLoaderUrls = new URL[]{new URL("file:///path on my computer/knime_2.9.4/jre/lib/endorsed/cdk-1.4.19.jar")};
URLClassLoader urlClassLoader = new URLClassLoader(classLoaderUrls);
Class<?> parserClass = urlClassLoader.loadClass("org.openscience.cdk.smiles.SmilesParser");
Class[] classParameters = new Class[] {IChemObjectBuilder.class};
Constructor<?> constructor = parserClass.getConstructor(classParameters); //until this line there are no problems
Object parser = constructor.newInstance(builder); //fails here with the same exception message: Could not initialize class org.openscience.cdk.smiles.SmilesParser
I am sure that this is not a CDK error because I can execute the code in Eclipse.
Why can a constructor of one class be called from KNIME without any problems and a constructor of another class can not??
I would be very grateful if you could suggest a solution or a probable reason why this happens.
Thank you!
Ok, finally solved the problem myself. Cleaned project meta data, cleaned endorsed library directory, switched KNIME workspace to another directory, put all jars into one folder and added them as external libraries. Now it works:)

NoClassDefFoundException when receiving object with readObject()

Here's my setup:
My server waits for IPlugin-Objects with an ObjectInputStream. The incoming IPlugin-Object is of an unknown class, so first, the class-file is transmitted and loaded by the classloader of the OIS. Then, the IPlugin itself is sent by the client. The cast of the IPlugin seems not to be a problem (when using my own classloader in the OIS). But the IPlugin uses jama and now I got an NoClassDefFoundException when I receive the object. The weird thing for me is, that in the servers classpath the Jama-library is contained. I also tried, to write a dummy-line, so the library will really be imported (and not ignored by the compiler).
Can anybody help me on that? It really bugs me...
Okay, I've got it:
The problem was, that my personal URIClassLoader got every URI possible, except the current classloader. Now the constructor looks like the following:
URLClassLoader loader = new URLClassLoader(new URL[]{pluginFolder.toURI().toURL()},
this.getClass().getClassLoader());

Why I got no super classes with getAllSuperclasses() in JDT API?

I have class A, and class B that inherits A in Eclipse workspace.
The issue that I have is that I got nothing when I tried to get the super types of type B using eclipse JDT API. This is the code (I got the code from - List all subclasses with fully qualified names):
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
java.io.File workspaceDirectory = root.getLocation().toFile();
// 1. The name of the project in the workspace
IProgressMonitor pm = new NullProgressMonitor();
IProject orig = root.getProject(this.projectName);
orig.open(pm);
this.javaProject = JavaCore.create(orig);
orig.refreshLocal(IResource.DEPTH_INFINITE, pm);
// 2. Find the type
IType type = this.javaProject.findType("p.B"); <-- returns correct type info
ITypeHierarchy hier = type.newSupertypeHierarchy(new NullProgressMonitor());
IType[] types = hier.getAllSuperclasses(type);
System.out.println(types); <-- Returns []
I also added the code to refresh/update the resources in package.
IPackageFragmentRoot[] packageFragmentRoots = this.javaProject.getPackageFragmentRoots();
for (IPackageFragmentRoot proot: packageFragmentRoots)
{
proot.getResource().refreshLocal(IResource.DEPTH_INFINITE, null);
}
Everything works fine except getting the hierarchical type information.
What might be wrong? Did I miss any setup before executing the API?
Mine is a headless RCP application.
This may be a temporary solution, but it worked for me.
Short Answer
Make a lib directory, and copy this rtstubs.jar into the directory.
You may need to refresh(F5) the eclipse IDE to see the jar file is included in the project.
Then, in "Java Build Path", you need to add this jar file.
After the inclusion of the jar file in package fragment, you'll get the class hierarchy.
Long Answer (why does this solve the issue)
CompilationUnitDeclaration (org.eclipse.jdt.internal.compiler.ast) and Hierarchy Resolver (org.eclipse.jdt.internal.core.hierarchy)
It has a field ignoreFurtherInvestigation, and a method hasErrors() returns this field.
org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver#resolve() method invokes hasError() to add type information to cache. However, without the inclusion of the jar file, the hasError() method always returns false to prevent any class hierarchical information is stored.
org.eclipse.jdt.internal.core.JavaProjectElementInfo
This class has cache initialization methods such as initializePackageNames and getProjectCache. In getProjectCache() method, package fragment element roots are loaded and added to the cache.
With the rtstubs.jar in the package fragment, the cache now contains all the Java class hierarchy. Without this setup, in the course of cache build up, the ignoreFurtherInvestigation filed is on, and hasError() method returns true not to contain the class hierarchical information to return just nothing.
ADDED
The other solution can be using IRegion.
How can I set the region (=set of java Elements) parameter in JDT TypeHierarchy?

Categories