0

I have some classes with this organisation

--> : Inherit 

TwittEntititesNetwork --> TwitterGephiStreamer

TwittGrapher          --> TwitterGephiStreamer

TwitterGephiStreamer is Abstract 
TwitterGephiStreamer have a method : myMethod()

Directory
    ./myApp.jar
    ./NetworkLogicDirectory/TwittGrapher.jar
    ./NetworkLogicDirectory/TwittEntititesNetwork.jar

I use this code to load dynamically the daughters classes (which are in another .jar file)

public static TwitterGephiStreamer LoadNetworkLogicJar() throws Exception
    {
        File dir = new File(NetworkLogicDirectory);
        URL[] urls = new URL[dir.listFiles().length];
        for(int i = 0;i < dir.listFiles().length;i++)
        {
            File s = dir.listFiles()[i];
            String url  = "file:///"+s.getAbsolutePath();
            urls[i] = new URL(url);

        }
        ClassLoader = new URLClassLoader(urls);

        if(defaultProps.containsKey("NetworkLogic") &&  !defaultProps.getProperty("NetworkLogic").isEmpty())
        {
            Class<?> networkLogicClassLoader = ClassLoader.loadClass("org.naoyun.gephistream.networklogic."+defaultProps.getProperty("NetworkLogic"));
            Object object = networkLogicClassLoader.newInstance();



            return (TwitterGephiStreamer) object;
        }
        else
        {
            throw new Exception("blabalbalbal ");
        }
    }

So it's have to return a TwitterGephiStreamer which I can use as a normal class and I can use myMethod() normally .

When I run on eclispe it's works well I don't have any error.

When I export my app as a runnable .jar (myApp.jar) it's throw me this error :

java.lang.ClassCastException: org.naoyun.gephistream.networklogic.TwittEntitiesNetwork cannot be cast to org.naoyun.gephistream.TwitterGephiStreamer
        at org.naoyun.utils.ConfigurationTools.LoadNetworkLogicJar(ConfigurationTools.java:62)
        at org.naoyun.TwitterStreamer.<init>(TwitterStreamer.java:34)
        at org.naoyun.TwitterStreamer.main(TwitterStreamer.java:26)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)

So, I don't know how to resolve this problem. Is my code creepy but Eclispe can handle it on the fly, or is there other stuff that I'm not up do date?

Thanks for your time !

Totetmatt
  • 1
  • 1
  • 3
  • Why are you creating new instances this way? – Paul Jan 08 '12 at 18:11
  • Well, if someone else create a Class that inherit from TwitterGephiStreamer, he just have to put a jar with his class in the proper directory and say that he wants to use his class. – Totetmatt Jan 08 '12 at 18:13
  • Are you sure that eclipse and your exported jar are using the same .class generated? – jenaiz Jan 08 '12 at 18:14
  • Your code is most definitely creepy. Creating your own classloaders is pretty advanced usage, and not at all recommended unless you have a very compelling reason. – skaffman Jan 08 '12 at 18:15
  • @jenaiz, well I guess yes, I just create runnable Jar with eclipse (I try with cleanning project and so on ...) – Totetmatt Jan 08 '12 at 18:31
  • @skaffman So what do you suggest ? I want to change the behavior of my app when I simply choose the class to use in a .propertes file. And if I develop my own class, I just want to add it on a directory and use it simply. – Totetmatt Jan 08 '12 at 18:31
  • @Totetmatt: So just add the JARs to your clssspath, and let Java figure it out. You don't need to instantiate your own classloaders to do that. – skaffman Jan 08 '12 at 18:49

2 Answers2

0

You probably have org.naoyun.gephistream.TwitterGephiStreamer included more than once on your dynamic classpath. When the subclass is loaded it loads a copy of TwitterGephiStreamer that is conflicting with a previous loaded copy.

Since, TwittGrapher.jar and TwittEntititesNetwork.jar depend on the same core classes/interfaces (i.e. TwitterGephiStreamer), I would suggesting putting those types in a separate utility jar. This should help eliminate any duplicated types on the classpath and provide for a clean jar dependency tree:

           myApp
          /     \
TwittGrapher  TwittEntitiesNetwork
        \         /
         TwittUtil
Brent Worden
  • 10,624
  • 7
  • 52
  • 57
0

You should not use Eclipse to build your executable jar but rather make one manually, e.g. using an Ant build script.

When Eclipse builds an executable jar it packages everything together in one tidy package, loading dependent jars through its own classloader, found in the "jarinjarloader" package you see referenced in your stack trace. This classloader can't find your external jar when it's not part of the "omni-jar" that Eclipse builds.

I've used the URLClassLoader in the past to successfully do what you're trying to do: load external jars at runtime. Here is a question on SO that explains how to use it: Is it possible to “add” to classpath dynamically in java?

This tutorial should help with using Ant to build an executable jar: Build an executable jar file by referencing your dependencies

This Ant tutorial is similar and shows how to do it with Eclipse, though it doesn't set the dependencies in the manifest. You'll need to do that for your core application classes, not any external jars to be loaded at runtime.

Community
  • 1
  • 1
Paul
  • 19,704
  • 14
  • 78
  • 96