United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4676532 : LTP: Unable to get XMLDecoder to use a specific class loader

Details
Type:
Bug
Submit Date:
2002-04-29
Status:
Resolved
Updated Date:
2003-09-26
Project Name:
JDK
Resolved Date:
2003-09-26
Component:
client-libs
OS:
solaris_8,windows_xp
Sub-Component:
java.beans
CPU:
x86,sparc
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.4.0
Fixed Versions:
5.0 (tiger)

Related Reports
Duplicate:
Relates:

Sub Tasks

Description
It seems to be impossible to get the XMLDecoder class to use a class loader
other than the default systemClassLoader when decoding an XML stream. I've
tested 2 methods to achieve this, both fail....

This is a major issue because it is not possible for example to load
packages into a system using the URLClassLoader and then use XMLDecoder to
instantiate objects contained in those packages.

The attached example demonstrates both attempts I've made to get XMLDecoder
to use a specific ClassLoader.

The code base attached includes a jar test.jar file which contains a simple
test.message class.

Running encode.sh will write a test.xml file representing an instance of
test.message

Running java decode will fail to load Decode the xml, putting test.jar
in the classpath will run java -cp test.jar:. decode

The sample code makes two attempts to use the Decoder.  Both tests
create a URLClassLoader which references test.jar

In the first test an owner object is created which is actually the
class test.message which has been loaded by the URLClassLoader. I then
use this owner object as the owner of XMLDecoder.

In the second test I instantiate XMLDecoder using reflection. The XMLDecoder
class is loaded by URLClassLoader (which has the test.jar reference), but
it still fails to decode.


All tests were run with JDK 1.4.0-b92 on SPARC Solaris 9b58

                                    

Comments
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
tiger

FIXED IN:
tiger

INTEGRATED IN:
tiger
tiger-b22


                                     
2004-06-14
SUGGESTED FIX

If this requires an API change then this can only be fixed for tiger. We can come up with an interim solution for Mantis:

Statement.classForName should use the Introspector.instantiate() method. The instantiate() method uses the classloader for a class (TBD), the system classloader and then the classloader from the current thread. This could be a good interim solution until a class loader can be explicitly specified through api.
###@###.### 2002-08-08


XMLEncoder should take a classLoader as it's argument. 
Or perhaps we should add new API:

public void setClassLoader(ClassLoader cl)
public ClassLoader getClassLoader();

com.sun.beans.ObjectHandler.classForName should examine the decider if it exists.

    public static Class classForName(String name) throws ClassNotFoundException {
        // l.loadClass("int") fails.
        Class primitiveType = typeNameToPrimitiveClass(name);
        if (primitiveType != null) {
            return primitiveType;
        }
	ClassLoader l = Thread.currentThread().getContextClassLoader();
	if (is != null && is.getClassLoader() != null) 
	    l = is.getClassLoader();
        }
        return l.loadClass(name);
    }
###@###.### 2003-09-05
                                     
2003-09-05
EVALUATION

It appears that the class loading from the name of the class is done through the static method Statement.classForName() method. This method is called from Statement.invoke() and is wrapped and called from XMLDecoder.classForName() - which is called from many places within XMLDecoder.

Statement.classForName() only uses the ContextClassLoader from the currentThread and there is no way that you can specify it to use a specific classloader. One possible solution is for the Statment to try loading the class from the classloader of the target object. The strategy would have to be similar to the one implemented in trying to load the explicit BeanInfo class within the Introspector.

###@###.### 2002-05-02

The class lookup within the Introspector should be the model of looking for classes. A good solution to this would be to refactor the static method Introspector instantiate method to use a static "search for class" method. The Statement classForName can use this package private class lookup mehtod.

Should be fixed for tiger. Perhaps in mantis if this becomes a larger issue.

###@###.### 2002-05-17
                                     
2002-05-17
WORK AROUND

The best way that I would recommend doing this is to patch Statement.classForName to try the target class loader first and then use the currentThread context class loader:

ClassLoader cl = target.getClassLoader();
if (cl != null) {
  try {
    return cl.loadClass(className);
  } catch (Exception ex) {
     // fall through
  }
}

Prepend this patched java.bean.Statement in front of your bootstrap classpath with -Xbootclasspath:/p.

=======================

Another more viable work around is to set the class loader that you want to instantiate within the current thread context:

Before instantiating the XMLDecoder, set the classloader that you want to use by:

	Thread.currentThread().setContextClassLoader(classloader);
        
###@###.### 2002-05-02

                                     
2002-05-02



Hardware and Software, Engineered to Work Together