Detect whether Java class is loadable - java

I have two programs: one CLI program, and one GUI. The GUI is a frontend for the CLI, but also a GUI for another program as well.
I am importing the CLI's classes and extending them in the GUI to add GUI elements to the classes, and all is great.
But now I want to split the CLI that I currently have embedded in the GUI (as an included JAR). The JAR is in a fixed location (/opt/program/prog.jar), and the application will only be used on Linux, so I realize that this breaks traditional Java thought.
I've edited the ClassPath in the Manifest file to reflect this change, and it works fine. However, when I remove the file, the GUI fails to load, citing not being able to load the class.
Is there a way to try to load a class and if it does not work, then do something else? In essence, I'm trying to catch the ClassNotFound exception, but have not had any luck yet.

One common way to check for class existence is to just do a Class.forName("my.Class"). You can wrap that with a try/catch that catches ClassNotFoundException and decide what to do. If you want, you could do that in a wrapper class that has a main(). You could try to load the class and if it succeeds, then call main() on the loaded class and if not, do something else.
public static void main(String arg[]) {
try {
Class.forName("my.OtherMain");
// worked, call it
OtherMain.main();
} catch(ClassNotFoundException e) {
// fallback to some other behavior
doOtherThing();
}
}

Is there a way to try to load a class and if it does not work, then do something else?
Assuming you had a class file in C:\ called Foo.class
public static void main(String[] args) {
File f = new File("c:\\");
if (f.exists()) {
URLClassLoader CLoader;
try {
CLoader = new URLClassLoader(new URL[]{f.toURL()});
Class loadedClass = CLoader.loadClass("Foo");
} catch (ClassNotFoundException ex) {
} catch (MalformedURLException ex) {
}
} else {
//do something else...
}
}

Related

Jumping to another class using a JButton

I have the below code where I made a simple GUI. I would like Button2 to navigate to class 'Project2', which should start another piece of code. Just to note, in its current state, 'Project2' has no GUI, though I intend to add one soon. Anyway, this 'code jump' which I used by adding: String[] args = {};
Project2.main(args);
is not working, as the IDE says 'IOException must be caught or thrown'. I know how this works, though I am not sure how to implement it in the program.
Thanks in advance!
You can try to use dynamic class loading for your program. Below you can find lambda, which calls main method from com.stackoverflow.ExternalCaller class.
If you do not like to use lambda, you can create a simple anonymous class.
button.addActionListener(s -> {
try {
Class<?> externalCaller = Class.forName("com.stackoverflow.ExternalCaller");
Method main = externalCaller.getDeclaredMethod("main", new Class[]{String[].class});
main.invoke(null, new Object[]{new String[0]});
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
});
ExternalCaller class in its turn looks something like that:
package com.stackoverflow;
public class ExternalCaller {
public static void main(String args[]) {
System.out.println("Hello World");
}
}
In result once you click on the button you will get Hello World output in console.
If you would like to work with external jars etc. please look on Process class. Quick example:
Process proc = Runtime.getRuntime().exec("java -jar External.jar");
Or even more on fork/exec. You can read From Runtime.exec() to ProcessBuilder for more details.
Hope this will help. Good luck.
In most of the IDE's, when you right-click on the Button2 in the Design(GUI) pane, you can travel through:
Events -> Actions -> actionPerformed().
And write this code in the selected method to switch classes:
this.setVisible(false); //turns off the visibility of the current class
outputClass out = new outputClass(); //creating the object of the class you want to redirect to
out.setVisible(true);//turns on the visibility of the class you want to redirect to

JarClassLoader - loading jars dynamically - how to?

I have seen many class loader questions, but still was not able to figure why, the error here.
I am writing a program which uses 2 versions of jars. One is needed to get content from older storage, and another to store content in new storage.
Since, I need either of the jar to be loaded at a time, I used JarClassLoader to create a proxy for adding one jar and loading its classes. But I face ClassNotFoundException.
public class HbaseMigrator implements Runnable {
public void run() {
JarClassLoader jcl = new JarClassLoader();
jcl.add("hadoop-0.13.0-core-modified-1.jar");
Object obj1 = JclObjectFactory.getInstance().create(jcl, "UserMigThreadImpl", toProcessQueue,threadName, latch,DBUtil,lock);
MigThread mig = JclUtils.cast(obj1, MigThread.class, jcl);
Thread.currentThread().setContextClassLoader(jcl);
try {
Method method = MigThread.class.getMethod("callthis", new Class[]{});
method.invoke(mig, new Object[]{});
// mig.callthis();
} catch( Exception e) {
e.printStackTrace();
} catch(Error er) {
er.printStackTrace();
}
}
}
Method called is:
public void callthis() {
DFSUtil = new DFSAccessAPIImpl();
.........
}
This class instantiation internally uses hadoop modified jar, which is not picked up from my classloader and it throws ClassNotFoundException.
What is that I am doing wrong ?
JarClassLoader used here is jcloader :
org.xeustechnologies.jcl.JarClassLoader
I experienced this problem with loading plugins to my application, so I decided to try to load all .class files from all jars in path. Maybe this code snipped from my app will help you.
https://bitbucket.org/rsohlich/plagdetector/src/432b52f252ff7647221b7e91b08731bd9cbe2a70/PlagDetectorSpring/src/main/java/cz/sohlich/app/service/impl/PluginHolderImpl.java

How do I load resources when using a classloader?

I'm using JarFile and JarURLConnection to load files out of a jar file. I'm then taking the classes, and loading them via BCEL (ByteCode Engineering Library, apache library). I cant just directly use a class loader because im modifying some classes slightly with the BCEL. I need to load the classes by their bytes into my bcel loader. However, one of the classes I'm loading references a resource. This resource is inside of the jar, so I can get the file (When iterating over the entries in the JarFile, I ignore the regular files, and take the class files for loading later). But just having the file won't do me any good, as the class loads it as a resource. Is there any way I can take that resource from the jar (well I can take it and load it into a byte[], the next part is the issue) and dynamically add it as a resource for my program, so that the classes that I load wont be missing their resources?
Got a lot of stuff here, if anythings confusing, ask in comments, I might've said something wrong, or missed something altogether :) Thanks
I'll show a little of my class loader here (extends ClassLoader):
#Override
public URL getResource(String name) {
System.out.println("LOADING RESOURCE: " + name);
try {
return new URL(null, name, new Handler(files));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Now, it is printing out "LOADING RESOURCE: filename", but its then giving me a MalformedURLException (I have no protocol atm, just a file path, that's not a true valid path, but it's just an attempt to give it to my Handler class below).
class Handler extends URLStreamHandler {
#Override
protected URLConnection openConnection(URL u) throws IOException {
return new URLConnection(u) {
#Override
public void connect() throws IOException {
}
#Override
public InputStream getInputStream() throws IOException {
System.out.println("IS: " + url);
return /*method to get input steam*/;
}
};
}
}
The /*method to get input steam*/ is set in my real code, but that's not relevant here. So any further ideas with this?

is there a way to check if a class has the main method?

I'm trying to get the list of all classes in a project in Java and I would like to identify the class where the main method is located. Is there a way to be able to identify that a class is implementing the main method, without actually looking at the code of the class itself?
I've implemented the following but the return value is always being false. does anyone know why this is happening?
Class<?> c = "edu.tool.parsing.A".getClass();
boolean hasMain = true;
try {
c.getMethod("main", String[].class);
hasMain=true;
} catch (SecurityException e) {
hasMain = true;
} catch (NoSuchMethodException e) {
hasMain=false;
}
Programmatically:
Class.getClass("com.mycompany.MyClass").getMethod("main", String[].class)
Or alternatively you can use command line utility javap that you can find in your JDK bin directory.
If you have the class name, then you can try to reflect the main method.
Trivial (inclomplete) approach:
private static hasMainMethod(Class<?> clazz) throws Exception {
Method[] methods = clazz.getMethods();
for (Mehthod method:methods) {
if (method.getName().equals("main") {
// Now we have to verify the method signature!
return true;
}
}
return false;
}
There may be more than one such class. There may be dozens. Why don't you know the entry point in advance? You might be better off looking at the Main-Class entry in the JAR Manifest.
Load your project in a IDE (I have worked with IDEA) then, add a local run, IDEA will list you all classes with main method.
If you don't have sources and there are just jar files, that's ok, just add the jar files as a library of a project and then create a RUN.

Chained classloader conundrum

I'm having some hard time with Java classloaders, maybe somebody could shed some light on this. I have extracted the essence of the problem to the follwing:
There are three classes - ClassLoaderTest, LoadedClass and LoadedClassDep. They are all on different paths.
ClassLoaderTest instantiates a new URLClassLoader - myClassLoader, priming it with the paths to the remaining two classes and it's own classloader (i.e. the application classloader) as parent. It then uses Class.forName("com.example.LoadedClass", true, myClassLoader) to load the LoadedClass through reflection. The LoadedClass imports the LoadedClassDep. If I run the above, using:
java -cp /path/to/the/ClassLoaderTest ClassLoaderTest "/path/to/LoadedClass" "/path/to/LoadedClassDep"
and using the command line arguments to prime the URLClassLoader everything works fine. Using static initialisers I confirm that the two classes are loaded with an instance of a URLClassLoader.
HOWEVER, and this is the problem, if I do:
java -cp /path/to/the/ClassLoaderTest:/path/to/the/LoadedClass ClassLoaderTest "/path/to/LoadedClassDep"
this fails to load the LoadedClassDep (ClassNotFoundException). The LoadedClass is loaded correctly, but with sun.misc.Launcher$AppClassLoader, not the URLClassLoader!
It would appear that since the application classloader is capable of loading the LoadedClass it also attempts to load the LoadedClassDep, disregarding the URLClassLoader.
Here's the full source code:
package example.bc;
public class ClassloaderTest {
public static void main(String[] args) {
new ClassloaderTest().run(args);
}
private void run(String[] args) {
URLClassLoader myClasLoader = initClassLoader(args);
try {
Class<?> cls = Class.forName("com.example.bc.LoadedClass", true, myClasLoader);
Object obj = cls.newInstance();
cls.getMethod("call").invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
private URLClassLoader initClassLoader(String[] args) {
URL[] urls = new URL[args.length];
try {
for (int i = 0; i < args.length; i++) {
urls[i] = new File(args[i]).toURI().toURL();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return new URLClassLoader(urls, getClass().getClassLoader());
}
}
package com.example.bc;
import com.bc.LoadedClassDep;
public class LoadedClass {
static {
System.out.println("LoadedClass " + LoadedClass.class.getClassLoader().getClass());
}
public void call() {
new LoadedClassDep();
}
}
package com.bc;
public class LoadedClassDep {
static {
System.out.println("LoadedClassDep " + LoadedClassDep.class.getClassLoader().getClass());
}
}
I hope I made this clear enough. My issue is, I only know the path to ClassLoadeTest at compile time, I have to use strings at runtime for the other paths. So, any ideas how to make the second scenario work?
I'd expect the application classloader to load LoadedClass in the second case, since classloaders delegate to their parent initially - this is the standard behaviour. In the second case, LoadedClass is on the parent's classpath, so it loads the class instead of giving up and letting the URLClassLoader try.
The application classloader then attempts to load the LoadedClassDep because it is imported and referenced directly in LoadedClass:
public void call() {
new LoadedClassDep();
}
If you need to load these classes dynamically and independently at runtime, you can't have direct references between them in this way.
It is also possible to change the order in which classloaders are tried - see Java classloaders: why search the parent classloader first? for some discussion of this.

Categories

Resources