Loading external classes - java

I am trying to load a class from a directory which I specify. I have done some research and made this:
ArrayList<Object> plugins = new ArrayList<Object>();
ClassLoader loader = Reflection.class.getClassLoader();
public Reflection()
{
load();
}
public void load()
{
File f = new File(Full directary);
ClassLoader loader = null;
try
{
loader = new URLClassLoader(new URL[]
{ f.toURI().toURL() }, getClass().getClassLoader());
}
catch (MalformedURLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
for (File classFile : f.listFiles(new FilenameFilter()
{
public boolean accept(File dir, String name)
{
return name.endsWith(".class");
}
}))
// Start for loop.
{
try
{
String filename = classFile.getName();
System.out.println(filename);
Class<?> cls = loader.loadClass(filename.replace(".class", ""));
System.out.println(cls.getSuperclass().getName());
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
I am getting aNoClassDefFoundError error:
Exception in thread "main" java.lang.NoClassDefFoundError: mTest123g (wrong name: net/xcaliber/reflection/Test)
It finds the class fine, but then can't load it. I have made a basic interface:
String getName();
That's all that's in it; here is the class I am loading:
public Test()
{
// TODO Auto-generated constructor stub
}
#Override
public String getName()
{
return "Test";
}
This does implement the interface.Let me know the problem with it .

Obviously you have a mess up with class and file names.
Exception in thread "main" java.lang.NoClassDefFoundError: mTest123g (wrong name: net/xcaliber/reflection/Test)
So, you loading it as java mTest123g. Class loader expects a mTest123g.class not a Test class inside some net.xcaliber.reflection package.

Related

Java runtime compiler using reflections not working properly

I have a JavaFX app where there is an editor. In the editor, the user will be able to write java code and I have a button to compile this code and run the main method. For example the editor will contain this code:
public class Test {
public static void main(String[] args) {
System.out.println("hello");
}
}
The button on click, will run this code:
runButton.setOnAction(e -> {
compiler.set(editor.getText());
try {
compiler.createFile();
} catch (IOException e1) {
e1.printStackTrace();
}
compiler.compile();
compiler.run();
});
In the compiler class, there is the following implementation:
public class CodeCompiler {
public String className;
public String code;
public void set(String code) {
try {
this.className = code.substring(code.indexOf(" class ") + 6, code.indexOf(" {")).trim();
} catch(StringIndexOutOfBoundsException e) {
}
this.code = code;
}
public void createFile() throws IOException {
PrintWriter pw = new PrintWriter("speech2code/src/main/java/" + className + ".java");
pw.close();
FileWriter writer = new FileWriter("speech2code/src/main/java/" + className + ".java", true);
writer.write(code);
writer.flush();
writer.close();
}
public void compile() {
File file = new File("speech2code/src/main/java/" + className + ".java");
File classFile = new File("speech2code/src/main/java/" + className + ".class");
classFile.delete(); // delete class file f it exists
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, file.getPath());
}
public void run() {
Class<?> cls = null;
try {
cls = Class.forName(className);
System.out.println(cls == null);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method meth = null;
try {
meth = cls.getMethod("main", String[].class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
String[] params = null;
try {
meth.invoke(null, (Object) params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Now the code above successfully creates the java file, class file and runs correctly the first time. Now when I change the editor code to print something else, it outputs the result of the first time the code was running. So, in this case, it will still print 'hello' instead of whatever it's current value.
Any problem what might be wrong?
Thanks!
You need to create a new classloader for the new class. The class does not get reloaded just because you compiled it.
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] {classFile});
Then you can ask this loader for the class:
Class<?> cls = Class.forName(className, true, classLoader);

Filtering all files from a folder and it's subfolders in java using FilenameFilter

I want to lsit all the files form a directory i get as a paramter that end in .java and have a certain text in them,I have issues when i want to do this for all of it's ssubfolders.
Using filenamefilter on a folder only returns the files in the folder not in it's subfolders.
Any ideea how I can make it work on the subfolders too?
I solved this problem and I am attaching my solution jsut in case somebody else bumps into this.Also,I used Threads because I found it easier to do it with Threads.
The ideea behind my solution was
one thread was in charge of getting all the files that end in ".java" [producer]
another parsing through those files to get the ones that contain a specific text
The Producer:
public class ThreadProducator extends Thread {
public Bufferino buffer ;
File directory ;
static ArrayList<File>files = new ArrayList<File>();
public ThreadProducator(Bufferino a){
this.buffer = a;
directory = new File("src");
}
public static ArrayList<File> getFiles(File f){
ArrayList<File> files1= new ArrayList<File>();
for ( File fis : f.listFiles()){
if ( fis.isDirectory()){
getFiles(fis);
}
else{
if(fis.getName().endsWith(".java")){
files.add(fis);
//System.out.println(files.toString());
}
}
}
return files;
}
public void run() {
// TODO Auto-generated method stub
if(directory.isDirectory()){
ArrayList<File>files =new ThreadProducator(buffer).getFiles(directory);
// System.out.println(files.toString());
buffer.put(files);
try {
sleep((int)Math.random()*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The Consumer:
public class ThreadConsumator implements Runnable {
private Bufferino buf;
String lookedFor = "asdas";
public ThreadConsumator(Bufferino bufi){
this.buf = bufi;
}
#Override
public void run() {
// TODO Auto-generated method stub
ArrayList<File> res = new ArrayList<File>();
String content="";
System.out.println("Files containing the word "+lookedFor+" are:");
for ( int i = 0 ; i <25;i++){
res = buf.get();
for (File f : res)
try {
content = new Scanner(f).useDelimiter("\\Z").next();
if(content.contains(lookedFor)){
System.out.println(f.getName());
}
/*System.out.println("-----------------------");
System.out.println(content);
System.out.println("-----------------------");*/
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

Importing a subclass when interface is not in subclass .jar

So i've decided to try to write a thing that will loads a specific .class file from a .jar that anyone puts into a folder. (Right now it only loads my Test.jar)
The thing is, that these classes implements an interface in the java project that i'm loading them from, and i get an error telling me that the class "Klass" doesn't exist.
How can i get the loader to load that one instead of trying to use it's own?
(Also, this is what i think it's doing, i have no idea if it's true)
The code for loading the .jar:
String filePath = new String("C:/classes/Test.jar");
URL myJarFile = null;
try {
myJarFile = new URL("file:///"+filePath);
URL[] urls = new URL[]{myJarFile};
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls);
// Load in the class; MyClass.class should be located in
// the directory file:/c:/myclasses/com/mycompan
Class cls = cl.loadClass("me.bluejelly.survivalgames.classes.Test");
try {
Klass klass = (Klass) cls.newInstance();
klass.create(arg0.getName());
Main.listeners.put(arg0.getName(), klass);
Bukkit.getPluginManager().registerEvents(klass, instance);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
And this it the code in the file i'm trying to load:
package me.bluejelly.survivalgames.classes;
import me.bluejelly.survivalgames.Main;
import me.bluejelly.survivalgames.def.Klass;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.ItemStack;
public class Test implements Klass {
private String ownerName;
#Override
public void create(String pName) {
this.ownerName = pName;
Main.listeners.put(this.ownerName, this);
}
#Override
public void destroy() {
if(Main.listeners.containsKey(this.ownerName)) {
Main.listeners.remove(ownerName);
}
HandlerList.unregisterAll(this);
}
#Override
public Material getIcon() {
return null;
}
#Override
public ItemStack[] getStartingItems() {
return null;
}
#EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
if(event.getPlayer().getName().equals(ownerName)) {
Bukkit.broadcastMessage("test");
}
}
}
You need to set the main class loader as the parent of your new URLClassLoader. That way it will pick up your local Klass class.
Something like...
ClassLoader cl = new URLClassLoader(urls, getClass().getClassLoader());

invoke method of class from jar using reflection

I want to invoke a method from class which is inside an external jar using reflection. But I am still not able to do it. I'm using the following code
public class Test {
public static void main(String[] args) throws Exception {
try {
// File JarFile = new File("C:\\dataRetrieval.jar");
//
// URLClassLoader cl = new URLClassLoader(new
// URL[]{JarFile.toURI().toURL()});
// JarFile.getClass();
DataRetrievalManagerServiceStub stub = new DataRetrievalManagerServiceStub(
"html//...............???wsdl");
Map<String, String> requestMap = new HashMap<String, String>();
requestMap.put("TelephoneNumber", "01028824332");
Object stubInstance = Class.forName("com.test.DataRetrievalManagerServiceStub").newInstance();
Object reqInstance = Class.forName("com.test.impl.GetOllehIdsForUserDocumentImpl").newInstance();
Method[] stubMethods = stubInstance.getClass().getMethods();
Method[] reqMethods = reqInstance.getClass().getMethods();
//Method[] resMethods = resInterface.getClass().getMethods();
for (Method method : reqMethods) {
String methodName = method.getName();
System.out.println(methodName);
}
for (Method method : reqMethods) {
String methodName = method.getName();
if (methodName.startsWith("set")) {
methodName = methodName.replace("set", "");
String value = null;
if (requestMap.containsKey(methodName)) {
value = requestMap.get(methodName);
}
method.invoke(reqInstance, value);
}
}
Object resInterface = Class.forName(
"com.test.GetOllehIdsForUserResponseDocument").getInterfaces();
} catch (AxisFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I get an error message shown below:
log4j:WARN No appenders could be found for logger (org.apache.axis2.description.AxisOperation). log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" java.lang.InstantiationException: com.kt.sdp.impl.GetOllehIdsForUserDocumentImpl
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source) at sdk.kt.com.Test.main(Test.java:78)
Does anyone have any idea?

Loading a class twice in JVM using different loaders

I have one question regarding concepts of class loading. How to load a .class file twice in JVM. I am also writing an excerpt of code that I have written to accomplish this..
1) Loader 1 code
public class MyClassLoader extends ClassLoader {
public MyClassLoader(){
super(MyClassLoader.class.getClassLoader());
}
public Class loadClass(String classname){
try {
return super.loadClass(classname);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
2) Loader 2 code
public class AnotherClassLoader extends ClassLoader {
public AnotherClassLoader(){
super(AnotherClassLoader.class.getClassLoader());
}
public Class loadClass(String classname){
try {
return super.loadClass(classname);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
3) Now i am loading a class named A using this two different class loaders. I suppose the operation classA1==newClassA should return false. Here is the code:
public static void main(String[] args) {
MyClassLoader loader1 = new MyClassLoader();
AnotherClassLoader newLoader = new AnotherClassLoader();
System.out.println("Load with Custom Class Loader instance");
Class classA1 = loader1.loadClass("com.hitesh.coreJava.A");
System.out.println("Class Loader:::"+classA1.getClassLoader());
Class newClassA = newLoader.loadClass("com.hitesh.coreJava.A");
System.out.println("Class Loader:::"+newClassA.getClassLoader());
System.out.println(classA1==newClassA);
System.out.println(classA1.hashCode() + " , " + newClassA.hashCode());
}
4) Result of executing above code:
Load with Custom Class Loader instance
Class Loader:::sun.misc.Launcher$AppClassLoader#11b86e7
Class Loader:::sun.misc.Launcher$AppClassLoader#11b86e7
true
1641745 , 1641745
Could you please explain this
Try this
public class Test1 {
static class TestClassLoader1 extends ClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (!name.equals("Test1")) {
return super.loadClass(name);
}
try {
InputStream in = ClassLoader.getSystemResourceAsStream("Test1.class");
byte[] a = new byte[10000];
int len = in.read(a);
in.close();
return defineClass(name, a, 0, len);
} catch (IOException e) {
throw new ClassNotFoundException();
}
}
}
public static void main(String[] args) throws Exception {
Class<?> c1 = new TestClassLoader1().loadClass("Test1");
Class<?> c2 = new TestClassLoader1().loadClass("Test1");
System.out.println(c1);
System.out.println(c2);
System.out.println(c1 == c2);
}
}
output
class Test1
class Test1
false
Both classloaders start the lookup in their parent classloader (that's what the super() call is about). So actually the super classloader loads it in both cases.
You can try this:
String pathToJar = "C:\\path\\to\\my.jar";
String className = "com.mypackage.ClassA";
URLClassLoader cl1 = new URLClassLoader(new URL[] { new URL(pathToJar) });
URLClassLoader cl2 = new URLClassLoader(new URL[] { new URL(pathToJar) });
Class<?> c1 = cl1.loadClass(className);
Class<?> c2 = cl2.loadClass(className);
System.out.println(c1);
System.out.println(c2);
System.out.println(c1==c2 ? "Parent classloader loads" : "Parent classloader does not load");
cl1.close();
cl2.close();
Make sure that my.jar is NOT on your classpath.
In both cases you are using the same ClassLoader to perform the loading. You have two ClassLoaders but each just call super.loadClass() which delegates to the same parent ClassLoader which is AppClassLoader.

Categories

Resources