1

From the answer in the link below Link

I found that it can be resolved by adding it to classpath. But I am using Custom ClassLoader to load jar axiom-impl-1.2.14. Is there any way to achieve this?

axiom jar is using ClassLoader. Enumeration getResources(String name) to load that xmls internally in jar. XML file in our case is residing in jar file. So I am looking for solution by which I can get file URL of the XML.

Source Code :

public class ExternalClassLoader extends ClassLoader {

private String jarFile = "";
private Hashtable<String, Class> classes = new Hashtable<String, Class>();

public ExternalClassLoader(String jarLocation) {
    super(ExternalClassLoader.class.getClassLoader());
    this.jarFile = jarLocation;
}

@Override
public Class loadClass(String className) throws ClassNotFoundException {
    return findClass(className);
}

@Override
public Class findClass(String className) {

    byte classByte[];
    Class result = null;
    System.out.println("CLASS : " + className);
    result = (Class) classes.get(className);
    if (result != null) {
        return result;
    }
    try {
        return findSystemClass(className);
    } catch (Exception e) {
    }
    JarFile jar = null;
    try {
        jar = new JarFile(jarFile);
        String classLocation = className.replace('.', '/');
        JarEntry entry = jar.getJarEntry(classLocation + ".class");
        InputStream is = jar.getInputStream(entry);
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        int nextValue = is.read();

        while (-1 != nextValue) {
            byteStream.write(nextValue);
            nextValue = is.read();
        }

        classByte = byteStream.toByteArray();
        result = defineClass(className, classByte, 0, classByte.length, null);
        classes.put(className, result);
        return result;
    } catch (Exception e) {
        System.out.println("ERROR CLASS : " + className);
        return null;
    } finally {
        try {
            jar.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

@Override
public InputStream getResourceAsStream(String name) {
    try {
        System.out.println("RESOURCE : " + jarFile + "//" + name);
        JarFile jar = new JarFile(jarFile);
        JarEntry entry = jar.getJarEntry(name);
        return jar.getInputStream(entry);
    } catch (IOException e) {
        System.out.println("ERROR RESOURCE : " + jarFile + "//" + name);
        return null;
    }
}

}

Community
  • 1
  • 1
NIKUNJ SANGHADIA
  • 342
  • 4
  • 15
  • 1
    Can you give some more details about what kind of class loading you are using? – Andreas Veithen Oct 15 '15 at 08:16
  • Actually I don't want to include this jars in my project as because of conflict risk. I wrote a simple custom class loader to load class in this jar. But I am facing problems because this jar internally uses getResources to load axiom.xml from class path. But I don't want to add it in classpath. – NIKUNJ SANGHADIA Oct 16 '15 at 01:16
  • Are axiom-api and axiom-impl loaded by the same class loader? – Andreas Veithen Oct 16 '15 at 11:14
  • Yes. Loaded by the same class loader. – NIKUNJ SANGHADIA Oct 19 '15 at 00:41
  • If axiom-api and axiom-impl are loaded by the same class loader, that class loader is a custom class loader and you get the error message in the title, then this means that your custom class loader doesn't implement resource loading correctly. To get an answer to your question you therefore need to show the code of that class loader. – Andreas Veithen Oct 19 '15 at 07:44
  • You said earlier that axiom-api and axiom-impl are loaded by the same class loader, but your custom class loader can only load classes from a single JAR. Please make sure that you provide precise, reliable and consistent information. – Andreas Veithen Oct 19 '15 at 21:32
  • All the external jars like axiom-api and axiom-impl, etc which I need are converted to a single jar using ant build. – NIKUNJ SANGHADIA Oct 20 '15 at 03:04

1 Answers1

1

Since you don't specify the details, I'm assuming that the conflict occurs with another version of axiom-impl that is in the classpath of the class loader the rest of your application is loaded from (Otherwise you could just use one or more URLClassLoader instances or change the class loading policy of your application class loader).

I'm also assuming that (as you mentioned in a comment) axiom-api and axiom-impl are both loaded by the same custom class loader or that you combined the classes from these two JARs into a single JAR (in which case I'm assuming that you don't include axiom-dom in the same JAR since that would cause additional problems).

If these assumptions are true, then what you need is a class loader that loads classes from one or more JAR files and that uses parent last as class loading policy. To achieve that, you don't need to reimplement the JAR loading logic as you attempted to do in the code you have posted. Instead you can use URLClassLoader, but you need to extend it to change its class loading policy from the default parent first to parent last. There is actually an example of this in the source code of Apache Axiom itself:

http://svn.apache.org/repos/asf/webservices/axiom/tags/1.2.15/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/ParentLastURLClassLoader.java

You can probably use that code as is, although you may want to remove the package filter on javax.* because that shouldn't be necessary in your case.

Andreas Veithen
  • 8,868
  • 3
  • 25
  • 28