3

I am using the following code to create an instance of OdbcIniTarget class which implements the Target interface. The OdbcIniTarget class already exists in the application but is located in a different package and now should be loaded from the target directory which is not in the class path.

...
// directory below is resolved to /D:/Workspace/<myproject>/targets/
private File targetsLocation = new File("targets");
...
private void loadTargets() {            

    URL url = null;
    try {
        url = targetsLocation.toURI().toURL();            
    } catch (MalformedURLException e) {

    }

    URL[] urls = new URL[]{ url };        
    URLClassLoader classLoader = new URLClassLoader(urls);

    try {

     Target target =
     (Target)classLoader.
     loadClass("ch.blah.targets.nope.OdbcIniTarget").
     newInstance(); // <--- this fails hard  

    } catch (...) {
     ...
    }            

    try {
        classLoader.close();
    } catch (IOException e) {

    }
}

I am getting the following exception.

java.lang.ClassNotFoundException: ch.blah.targets.nope.OdbcIniTarget
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at ch.blah.targets.TargetFactory.loadTargets(TargetFactory.java:74)
    at ch.blah.targets.TargetFactory.<init>(TargetFactory.java:41)
    at ch.blah.SomeOfMyClasses.<init>(SomeOfMyClasses.java:34)
    at ch.blah.TheMainClass.main(TheMainClass.java:38)

Does someone have an idea why the class is not found?

The class which is loaded looks as follows.

package ch.blah.targets.nope;

import org.apache.log4j.Logger;

import ch.blah.utils.Utils;

public class OdbcIniTarget extends Target {

    private static final Logger log = Logger.getLogger(OdbcIniTarget.class);    

    @Override
    public boolean someMethod1() {
        return false;
    }

    @Override
    public boolean someMethod2() {
        return false;
    }

    @Override
    public boolean someMethod3() {
        return false;
    }       

    @Override
    public void someMethod4() {
        log.debug("Blah.");
        Utils.getInstance().marshalClass(SomeClass.class);
        log.debug("Finished.");
    }
}

The directory structure for targets directory is as follows.

D:\Workspace\<myproject>\targets>dir
 Volume in drive D is DATA
 Volume Serial Number is 021C-EC9B

 Directory of D:\Workspace\<myproject>\targets

10.07.2014  21:20    <DIR>          .
10.07.2014  21:20    <DIR>          ..
10.07.2014  21:31             1'278 OdbcIniTarget.java
10.07.2014  20:23             3'761 OdbcIniTargetConfiguration.java
               2 File(s)          5'039 bytes
               2 Dir(s)   7'328'571'392 bytes free
Tony Stark
  • 2,318
  • 1
  • 22
  • 41

2 Answers2

2

Problem:

It is failing to load because it doesn't contain classes at that URL, it has java source

Solution:

Compile those java classes to .class file and then pass the url to the directory which should look like

ch\blah\targets\nope\OdbcIniTarget.class
jmj
  • 237,923
  • 42
  • 401
  • 438
  • Please don't tell me it is not possible to compile just in time with java?! – Tony Stark Jul 10 '14 at 20:59
  • just in time compilation is different thing than source compilation, if you meant you want to compile java to class at runtime you can do it by using compiler API http://stackoverflow.com/questions/1064259/how-can-i-compile-and-deploy-a-java-class-at-runtime – jmj Jul 10 '14 at 21:01
  • but I wonder what are you trying to achieve, why can't you just compile before executing them? – jmj Jul 10 '14 at 21:14
  • I want to load modules (think plug-ins) that change very often and are placed in the file system as Java source code into the main application without being forced to re-compile the whole application. – Tony Stark Jul 10 '14 at 21:17
1

try passing the caller's classloader as a parameter in the constructor:

URLClassLoader classLoader = new URLClassLoader(urls, getClass().class.getClassLoader());

the class is a direct child of the dir in the url, so you need no package:

Target target =
 (Target)classLoader.
 loadClass("OdbcIniTarget").
 newInstance();
EduSanCon
  • 1,749
  • 1
  • 11
  • 9
  • Nope, this fails too. I also tried things like setting `Thread.currentThread().setContextClassLoader(classLoader);` but it still fails. – Tony Stark Jul 10 '14 at 20:47