kamranzafar / JCL

Jar Class Loader, a configurable and dynamic custom classloader designed to create, manage and manipulate isolated Java classloaders in IoC frameworks and web applications.
http://kamranzafar.github.com/
582 stars 162 forks source link

Loadin Java Service Provider Interface (SPI) from JAR via JCL #32

Closed Dc1975 closed 8 years ago

Dc1975 commented 9 years ago

I load the "lucene-core-4.10.3.jar" via JCL, it works fine.

Then I create my Class as follows : Object[] arguments = new Object[] { "Param" }; Class[] parameter = new Class[] { String.class };

    JclObjectFactory factory = JclObjectFactory.getInstance();

    Object obj = factory.create(jcl,
            "my.package.impl",
            arguments, parameter);

The constructor of my implementation creates the Lucene "IndexWriterConfig" object which uses the SPI "META-INF/services/org.apache.lucene.codecs.Codec" of the "lucene-core-4.10.3.jar".

The problem is that the SPI - classes were not loaded. Is this a problem of my coding, has anyone a suggestion?

mumrah commented 9 years ago

Maybe you need to pass the JCL class loader to the ServiceLoader? https://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html#load(java.lang.Class, java.lang.ClassLoader)

Otherwise it might be a problem with how JCL deals with resources (i.e., ServiceLoader not being able to locate and load META-INF/services/org.apache.lucene.codecs.Codec)

dkobylarz commented 9 years ago

It seems that JCL classloader does not work with SPI at all. Normally when you run the following program with lucene-core-4.7.0.jar in the classpath:

import java.util.Iterator;
import java.util.ServiceLoader;

public class SPITest {

    public static void main(String[] args) throws ClassNotFoundException {

        ClassLoader jcl = SPITest.class.getClassLoader();

        Class<?> codecClass = jcl.loadClass("org.apache.lucene.codecs.Codec");

        ServiceLoader<?> loader = ServiceLoader.load(codecClass);

        int c = 0;

        for( Iterator<?> iterator = loader.iterator(); iterator.hasNext(); ) {

            c++;

            System.out.println("Codec: " + iterator.next());

        }

        System.out.println("Codecs count: " + c);

    }

}

it prints the available codecs list

Codec: Lucene40
Codec: Lucene3x
Codec: Lucene41
Codec: Lucene42
Codec: Lucene45
Codec: Lucene46
Codecs count: 6

But similar program using JCL and loading lucene-core jar dynamically (lucene core jar not in the classpath) does not find any codecs:

import java.util.Iterator;
import java.util.ServiceLoader;
import org.xeustechnologies.jcl.JarClassLoader;

public class SPITest2 {

    public static void main(String[] args) throws Exception {

        JarClassLoader jcl = new JarClassLoader();

        jcl.add("lucene-core-4.7.0.jar");

        Class<?> codecClass = jcl.loadClass("org.apache.lucene.codecs.Codec");

        ServiceLoader<?> loader = ServiceLoader.load(codecClass, jcl);

        int c = 0;

        for( Iterator<?> iterator = loader.iterator(); iterator.hasNext(); ) {

            System.out.println("Codec: " + iterator.next());

            c++;

        }

        System.out.println("Codecs count: " + c);

    }

}

Output: Codecs count: 0

The JCL is instance is provided to service loader.

radimk commented 9 years ago

This is a dealbreak for me and a reason why I need to throw jcl away and go back to URLClassLoader.

kamranzafar commented 9 years ago

Will look into this issue.

hadfield commented 8 years ago

any ETA for fixing this issue?

kamranzafar commented 8 years ago

This will be fixed in the next release, due this week.

kamranzafar commented 8 years ago

Fixed in version 2.7.

Alex-Ikanow commented 8 years ago

Any chance I can reopen this?

I just jumped from 2.4 to 2.7 (to fix the intermittent Java8 concurrent modification exception), and now I can no longer create an Elasticsearch (1.7 aka Lucene 2.10.4) Client object, eg

Thread.currentThread().setContextClassLoader(jcl_classloader);

                final ImmutableSettings.Builder test_settings = 
                        ImmutableSettings.settingsBuilder()
                            .put("cluster.name", "aleph2")
                            .put("node.gateway.type", "none")
                            .put("index.store.type", "memory")
                            .put("index.number_of_replicas", 0)
                            .put("index.number_of_shards", 1)
                            .put("node.http.enabled", false);                                       
                NodeBuilder.nodeBuilder().settings(test_settings).loadConfigSettings(false).node();             

will exception out with

An SPI class of type org.apache.lucene.codecs.Codec with name 'Lucene410' does not exist.  You need to add the corresponding JAR file supporting this SPI to your classpath.  The current classpath supports the following names: []: IllegalArgumentException]:[NamedSPILoader.java:109:org.apache.lucene.util.NamedSPILoader:lookup]

Identical code works with 2.4, 2.5, 2.6

(EDIT: obviously I can provide more details, just wanted to give an overview of the issue to start with)