Bug 74 : Classpath search not working in resin 2.1.17 - No entities found
Priority 
High
Reported Version 
 
Logged By 
Rob
Status 
Fixed
Fixed Version 
1.0.3
Assigned To 
 
Product 
Ebean - core
Duplicate Of 
 
Created 
19/02/2009
Updated 
19/02/2009
Type 
Bug
 
Attachments 
No attachments

From Anton...

I've downloaded your sources and compiled them myself to see if I could narrow it down... and I did!

The problem lies in the class com.avaje.ebean.server.util.ClassPathSearch in partical this method:
private void initClassPaths() {
try {
classPaths = ((java.net.URLClassLoader) classLoader).getURLs();
} catch (ClassCastException e) {
classPaths = System.getProperty("java.class.path", "").split(File.pathSeparator);
}
if (logger.isLoggable(Level.FINER)) {
String msg = "Classpath " + Arrays.toString(classPaths);
logger.finer(msg);
}
}

The classloader resin 2.1.17 is giving us is the com.caucho.java.CompilingClassLoader which in particular is not an instance of java.net.URLClassLoader, so you get the classcastexception your code is catching. But the system-property java.class.path is not filled with the web-application jars/classes, so that's the reason for not running under resin 2.1.17. Resin 3.x gives you the option to specify classloaders via their config-files, so it can probably work without adjustments for resin 3.x, but I need resin 2.1.17 for some applications we have in production....

I've tried searching for a general way besides getUrls() to get all the resource-paths from a classloader, but I didn't find anything alike. So for my application I've hacked the method like this:
private void initClassPaths() {
try {
classPaths = ((java.net.URLClassLoader) classLoader).getURLs();
} catch (ClassCastException e) {
try {
classPaths = classLoader.getClass().getMethod("getClassPath").invoke(classLoader).toString().split(File.pathSeparator);
} catch (Throwable ex) {
classPaths = System.getProperty("java.class.path", "").split(File.pathSeparator);
}
}
if (logger.isLoggable(Level.FINER)) {
String msg = "Classpath " + Arrays.toString(classPaths);
logger.finer(msg);
}
}
This works because com.caucho.java.CompilingClassLoader implements the interface com.caucho.util.CauchoClassLoader which amongst others specifies this method:
public String getClassPath();

Do you know any general ways to retrieve all resource-paths from a classloader? That whould certainly make my hack unneccesary....

 
Rob 19 Feb 10:01
Make the class path reader pluggable

There is no general way to get the class paths (that I know of)...

The solution I have come up with is to make the implementation that determines the class paths pluggable. The interface is ClassPathReader and if the default implementation (DefaultClassPathReader) does not do the trick you can write your own and specify Ebean to use it via ebean.properties.

#
# (in ebean.properties)
# Specify your own ClassPathReader implementation
#
ebean.classpathreader=com.banana.MyClassPathReaderImplementation

public interface ClassPathReader {

/**
* Return the paths in the classpath to search for entity beans etc.
*


* This will typically return a URL[] or String[] of the entries in the
* class path.
*


*/
public Object[] readPath(ClassLoader classLoader);
}

Rob 19 Feb 10:04
Fixed in v1.0.3

I have incorporated this into v1.0.3.

Note: The majority of people will find their ClassLoader extends URLClassLoader and the default implementation will be fine.

Also note that I've added some more warnings logged when there appears to be an issue such as no classpaths etc so hopefully that extra detail will make things clearer when there is a classpath searching issue.

woResponse

Upload a file