0

I'm a beginner at java Reflection/Dynamic Loading. I want to load a specific Class ( that implements an Interface ) from a jar-File. Further more i want to initialize an Object of this Class and cast it to my specific Interface.

I tried .loadClass(), class.forName() and if I cast Myclass.newInstance to my Interface I'll get a ClassCastException.

How could I program my plugin-Loader, so it loads my class in my jar and cast it to myInterface?

Edit

My Server has the same Interface as my Plugins implement. Now I want my Plugins "loaded" and cast to my Interface so I could use them normally.

Edit

Here is some sample Code of my try to get a rid of these errors :D

URL url = f.toURL();  
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);

Class<ModInterface> c = (Class<ModInterface>)cl.loadClass("com.myapp.mod");

Class<? extends ModInterface> sub = c.asSubclass(ModInterface.class);
Constructor<? extends ModInterface> con = sub.getConstructor();
ModInterface mi = con.newInstance();

another code sample what I've done:

               ClassLoader loader = PluginLoader.class.getClassLoader();
               URL url = new URL("jar:file:" + f.getAbsolutePath() + "!/");
               URLClassLoader ucl = new URLClassLoader(new URL[] { url }, loader);
               Class iInterfaceClass = Class.forName("com.myapp.mod", true, ucl);
               ModInterface mi = (ModInterface) iInterfaceClass.newInstance();

Error:

java.lang.ClassCastException: com.myapp.mod cannot be cast to myapp.ModInterface

After some help provided by you i've done the following:

URL url = f.toURI().toURL();
   URL[] urls = new URL[]{url};
   ClassLoader loader = ModInterface.class.getClassLoader();
   ClassLoader cl = new URLClassLoader(urls, loader);
   Class<?> loadedClass = Class.forName("com.myapp.mod", true, cl);
   Class<? extends ModInterface> pluginClass = loadedClass.asSubclass(ModInterface.class);
   ModInterface mi = pluginClass.newInstance();

Now i get this error -> java.lang.ClassCastException: class com.myapp.mod thrown at loadedClass.asSubclass(..); The specific class is found, because if i change com.myapp.mod to whatever it throws a classnotfound execption. I've tried to use the ModInterface ClassLoader, but nothin changed. with(out) i'll get the same error.

Note:// I use 2 Projects. 1 for my Server App, the other for my Plugin that should be loaded. Both have the same Interface.

edit://

with this code i get an Object of type Object from my desired class, but it's not an instance of my ModInterface although my Class implements my ModInterface. If i try to cast my Object to my ModInterface a Error appears. Here is my short code:

Class c = clazzLoader.loadClass(element.getName().replaceAll(".class", "").replaceAll("/", "."));
Object instance = c.newInstance();
  • 1
    Care to post the code you have tried? Also, do you have a reason for using reflection? Having the compiler ensure type safety of your code is generally preferred, unless you have something that _must_ be deferred until runtime. – Colin M Jul 22 '13 at 12:43
  • I failed a bit, i want to load a class from a Jar-file and this class implements an interface. The generated Object should be casted to this known Interface so i could use this normally in my plugin-loader. And no i don't have Problems with posting my code, but i can't answer my topic within 8 hours, as it appears in Rules. – user2606815 Jul 22 '13 at 12:47
  • You don't need to _answer your topic_. Just edit your question and post the code. – Colin M Jul 22 '13 at 12:48
  • code added, hope you could help me :) – user2606815 Jul 22 '13 at 12:54
  • There is no need to add the major tag in the title. – Andrew Thompson Jul 22 '13 at 13:29
  • ok sorry i just want to be specific as possible within my topic – user2606815 Jul 22 '13 at 13:58

3 Answers3

1

It seems you know the concrete names of the class that implements the interface and must be instantiated. In that case the following will work:

Consider the following interface

package test.api;
public interface Plugin {
    void service();
}

with the following implementation

package test.impl;
import test.api.Plugin;
public class PluginImpl implements Plugin {
    @Override
    public void service() {
        System.out.println(":-)");
    }
}

Then the following code snippet will do what you want (and prints out ":-)"):

Class<?> loadedClass = Class.forName("test.impl.PluginImpl");
Class<? extends Plugin> pluginClass = loadedClass.asSubclass(Plugin.class);
Plugin plugin = pluginClass.newInstance();
plugin.service();

You can also get the correct class reference by using an appropriate class loder (as you did in your code example).

Note, that Class.forName returns a Class<?>, which must be cast afterwards. This cast can better be done with Class.asSubClass. If the loaded class does not implement the interface, you will just get a ClassCastException.

However ... If you want to build up a simple plugin mechanism, you should consider using a ServiceLoader, which requires your pluggable JARs to define a service configuration file. See the link for more explanation.

BTW: The class to be loaded in your code example looks more like a package name, so that it cannot be found. Maybe this is your problem?

Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66
  • this could be also my Problem. i got my file-handle with my absolute Path to my jar, i defined that in every plugin it has to be a path called com.myapp.mod. Mod is the class that implement my interface and which is recognized by my server. Now i try to load the class over my filehandle, i know that the class i ve to load is called com.myapp.mod. – user2606815 Jul 22 '13 at 14:06
  • My Path is right and my Class gets found but if i try to use .asSubClass(..) i get an Error. See above. – user2606815 Jul 22 '13 at 15:25
0

Well it seems you want to dynamically load the interface say A , as well as the implementing class say B. You can do it via reflection as :

Class<?> bClass = Class.forName("packagename.B", true, loader);
Class<?> aClass = Class.forName("packagename.A", true, loader);
Object bObject = // create an instance of class B via Reflection
Object aObject = aClass.cast(bobject);

Remember, both the class definitions has to be loaded from a class loader that is a common parent for both. The only purpose the cast serves here to ascertain that indeed B is a subtype of A.

Class#cast() :

Casts an object to the class or interface represented by this Class object.

Reflection tutorial will help you to know hoe to create instances reflectively.

AllTooSir
  • 48,828
  • 16
  • 130
  • 164
  • i add this to the comments above, i actually have an interface that all of my plugins have to implement. My Server have also this Interface, i only want to load a class and cast it to my Interface. – user2606815 Jul 22 '13 at 13:00
0

I solved my Problem myself. I've done a client lib that integrate my ModInterface. After that i added this .jar to my Projects, so both have the same Modinterface-Base. After this step ClassLoader.LoadClass is possible without any Casting-Exceptions.

Thanks for your help