Giter VIP home page Giter VIP logo

jcl's Issues

not support a class's static methods

I try to use JCL to load a class and use its static methods, but I am failed. I found out static methods are supported in Java 1.8 interface. But it seems JCL does not work even I use this new feature.

Can you help confirm this? Thanks.

license

all the source code only include the LGPL license, however the main page says i can use apache..

do i have permission to use this under the apache license instead of lgpl?

getResource in local loader is broken

getResource in the local loader throws an exception if no jar has ever been loaded.
This is incorrect: it should return NULL so other loaders have a chance of returning the resource.

Note that PR #24 fixes this issue as well and I strongly suggest to accept it.

Struggling with class casting

I have what is a relatively simple/standard setup; a plugin design pattern.

I can create the plugin in the new JCL classloader and get a reference to it with no problems. I create the reference to the interface using:

myPlugin = JclUtils.cast(...)

Now any method that I pass in standard JDK objects; no problems whatsoever. Everything is happy. However the problem is when i am attempting to get at a function that is passing a custom interface to it.

So my main callable interface is:

public IJobResult handle( IJobMessage job )

I create an instance of IJobMessage in the main code and when i attempt to call myPlugin.handle() it keeps

com.sun.proxy.$Proxy0 threw unexpected java.lang.reflect.UndeclaredThrowableException

with no such method. I have tried to JclUtils.cast() on the object that implements IJobMessage but that doesn't work either.

So the question is, how do I create an object in the base code and pass that to my loaded plugin loaded by JCL?

Thank you for assistance you can lend

2.7 release?

Wondering when we can expect the 2.7 release. The improvements to resource handling would be nice :)

Deadlock in version 2.7

thread busy-map-server-莲花洞-6-0:
java.lang.Thread.State: BLOCKED
at java.lang.ClassLoader.checkCerts(ClassLoader.java:884)
- waiting to lock <13bdd6ad> (a org.xeustechnologies.jcl.JarClassLoader) owned by "login-executor-0" t@301
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:665)
at java.lang.ClassLoader.defineClass(ClassLoader.java:758)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at org.xeustechnologies.jcl.JarClassLoader.access$000(JarClassLoader.java:42)
at org.xeustechnologies.jcl.JarClassLoader$LocalLoader.loadClass(JarClassLoader.java:246)
at org.xeustechnologies.jcl.AbstractClassLoader.loadClass(AbstractClassLoader.java:120)
- locked <789824e1> (a java.util.Collections$SynchronizedRandomAccessList)
at org.xeustechnologies.jcl.AbstractClassLoader.loadClass(AbstractClassLoader.java:94)
at org.reflections.ReflectionUtils.forName(ReflectionUtils.java:376)
at org.reflections.ReflectionUtils.forNames(ReflectionUtils.java:397)
at org.reflections.Reflections.getSubTypesOf(Reflections.java:367)

Locked ownable synchronizers:
- locked <12e5f7cb> (a java.util.concurrent.ThreadPoolExecutor$Worker)

thread login-executor-0:
java.lang.Thread.State: BLOCKED
at org.xeustechnologies.jcl.AbstractClassLoader.loadClass(AbstractClassLoader.java:117)
- waiting to lock <789824e1> (a java.util.Collections$SynchronizedRandomAccessList) owned by "busy-map-server-莲花洞-6-0" t@205
at org.xeustechnologies.jcl.AbstractClassLoader.loadClass(AbstractClassLoader.java:94)

JNI locked monitors:
- locked <13bdd6ad> (a org.xeustechnologies.jcl.JarClassLoader)

Locked ownable synchronizers:
- locked <33c6c4f> (a java.util.concurrent.ThreadPoolExecutor$Worker)

any suggestion?

JarClassloader reports incorrect URL's for resources.

Example code:
jarClassLoader.getResource("some-resources.xml");

This method has a high likelihood of return the wrong URL for the requested resource. The URL will reflect the last jar loaded by JarResources and not the actual jar where the resource is located.

This issue results from the fact that JarResources has a single baseUrl but is capable of loading resources from multiple jars. I have a change to track baseUrls of the resources in JarResource by changing from Map<String, byte[]> to Map<String, JclJarResource> and will submit a patch.

Android suporte

Do not know if that library should work on android, but the test did not get good results.

package com.example.JavaDN;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import org.xeustechnologies.jcl.JarClassLoader;
import org.xeustechnologies.jcl.JclObjectFactory;

import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends Activity implements Runnable {

    JarClassLoader mJcl;
    TextView log;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mJcl = new JarClassLoader();

        log = (TextView) findViewById(R.id.log);

        new Thread(this).start();
    }

    @Override
    public void run() {
        log.setText("Loading lib...");
        try {
            mJcl.add(new URL("https://dl.dropboxusercontent.com/u/67269258/lib_class.jar"));
        } catch (MalformedURLException e){
            e.printStackTrace();
        }

        JclObjectFactory factory = JclObjectFactory.getInstance();

        //Create object of loaded class
        Object obj = factory.create(mJcl, "Math");

        log.setText("ready! " + obj);
    }
}

Error:

06-08 19:17:15.799    7604-7617/com.example.JavaDN E/dalvikvm﹕ ERROR: defineClass(0x4261d390, Math, 0x42691238, 0, 812)
06-08 19:17:15.799    7604-7617/com.example.JavaDN W/dalvikvm﹕ threadid=11: thread exiting with uncaught exception (group=0x41bef700)
06-08 19:17:15.804    7604-7617/com.example.JavaDN E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-3011
    org.xeustechnologies.jcl.exception.JclException: java.lang.UnsupportedOperationException: can't load this type of class file
            at org.xeustechnologies.jcl.JclObjectFactory.create(JclObjectFactory.java:102)
            at org.xeustechnologies.jcl.JclObjectFactory.create(JclObjectFactory.java:85)
            at com.example.JavaDN.MainActivity.run(MainActivity.java:44)
            at java.lang.Thread.run(Thread.java:841)
     Caused by: java.lang.UnsupportedOperationException: can't load this type of class file
            at java.lang.VMClassLoader.defineClass(Native Method)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:292)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:256)
            at org.xeustechnologies.jcl.JarClassLoader.access$000(JarClassLoader.java:50)
            at org.xeustechnologies.jcl.JarClassLoader$LocalLoader.loadClass(JarClassLoader.java:254)
            at org.xeustechnologies.jcl.AbstractClassLoader.loadClass(AbstractClassLoader.java:122)
            at org.xeustechnologies.jcl.AbstractClassLoader.loadClass(AbstractClassLoader.java:95)
            at org.xeustechnologies.jcl.JclObjectFactory.create(JclObjectFactory.java:100)
            at org.xeustechnologies.jcl.JclObjectFactory.create(JclObjectFactory.java:85)
            at com.example.JavaDN.MainActivity.run(MainActivity.java:44)
            at java.lang.Thread.run(Thread.java:841)

unload whole jarFile

Hey there,
not sure, if this is the right place for my question. I'm currently working on a launcher for my java-app. This launcher loads a jarFile with your JavaClassLoader and starts the main app. Now, I want to update this jarFile, but it is locked (maybe by the ClassLoader?).
Is there a possibility to unload the whole jarFile to replace it with a newer one?

Greetings from Germany
Fabian

JCL to load plugin.jar with driver inside

Hi,
I'm a server side Java app (run with maven jetty) and I need to load, when required, a plugin.jar that is outside the classpath.
I do this with this code:

JarClassLoader jcl = new JarClassLoader();
jcl.add(pluginFile.getPath());
JclObjectFactory factory = JclObjectFactory.getInstance();

            // Create object of loaded class

            JarFile jarFile = new JarFile(pluginFile);
            Enumeration<JarEntry> e = jarFile.entries();
            while (e.hasMoreElements()) {
                JarEntry je = (JarEntry) e.nextElement();
                if (je.isDirectory() || !je.getName().endsWith(".class")) {
                    continue;
                }
                // -6 because of .class
                String className = je.getName().substring(0, je.getName().length() - 6);
                className = className.replace('/', '.');
                Object obj = factory.create(jcl, className);
                log.debug("Classe restituita: "+obj);
                return obj;
            }

then I invoke a method from this plugin class, say doSomething().

My plugin class in short make an access to a datasource (Dmbs) and inside is is included the jar needed to access the db.

in my doSomething() method I do this:

JarClassLoader jcl = new JarClassLoader();
jcl.add(".");
JclObjectFactory factory = JclObjectFactory.getInstance();
// Create object of loaded class
Object obj = factory.create(jcl, "com.mysql.jdbc.Driver");
Class.forName(dataSet.getDriver(), true, jcl);

Unfortunally when my server app try ti invoke doSomething() method I've always this exception:

26/07/2014 10:17:01 ERROR PluginManager:70 -
java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/db
at java.sql.DriverManager.getConnection(DriverManager.java:689)
at java.sql.DriverManager.getConnection(DriverManager.java:247)

Jcl is supposed to solve this situation?

Thanks

Any chance to dual-license JCL?

I wonder if you have any plans for dual-licensing the JCL library? I would like to use it for an open source project (Micro), project licensed under the Apache 2.

Thank you,
-florin

ClassLoader order is broken

By default, JCL uses the local loader for loading classes. Hence, JCL will by default always prefer its own loader to load classes from the jar. However, this makes it impossible for the application code to pass arguments to dynamically loaded classes, as the arguments use the application's class loader, where as the dynamic class' method parameter types use the JCL class loader:

Let's assume these classes are both in the application code and the imported Jar:

class Engine { }
interface Car { void setEngine(Engine engine); }

Then this does not work:

JarClassLoader jcl = new JarClassLoader();
jcl.add("fancyCars.jar"); // Contains class FancyCar implements Car {}
Object o = factory.create(jcl, "FancyCar");
Car car = JclUtils.cast(o, Car.class);

Engine engine = new DefaultEngine(); // Create some engine

// This statement breaks:
car.setEngine(engine);

// Reason:
// engine.getClass().getClassLoader() uses the application's class loader, whereas
// the Engine class that appears as the parameter type of FancyCar::setEngine is loaded via JCL

Per documenation, a work around should be to simply use the local class loader last, however this leads to another required workaround:

jcl.getLocalLoader().setOrder(100);

// This is a workaround to force updating the internal order of loaders;
// as of jcl 2.9-SNAPSHOT, there is no e.g. jcl.updateLoaderOrder() method
// I suggest to introduce it.

jcl.addLoader(jcl.getLocalLoader()); // Adding a loader updates the order

Some suggestions

Hi kamranzafar!

First, JCL is really great! I made some small modifications to JCL for my Webstart project. I don't know if they could be useful to others so I post them here

The first one is some kind of destroy method for JarClassLoader. It's useful for me because I have some kind of multigame and use this method to unload claseses and resources from JarClassLoader when not in use. (after seeing the unloadClass of JarClassLoader, maybe the unloading of resources could be done with the unloadClass(key) method too).

    public void destroy() {
      for (String key : getLoadedClasses().keySet())
        unloadClass(key);
      for (String key : getLoadedResources().keySet())
        classpathResources.unload(key);
    }

The second one is more related to the webstart and the ProtectionDomain/CodeSource. For that working I had to update public Class loadClass(String className, boolean resolveIt) of LocalLoader, to include in the defineClass method the protectionDomain (Maybe this is related to #1 issue Set ProtectionDomain/CodeSource??.

result = defineClass( className, classBytes, 0, classBytes.length, getClass().getProtectionDomain());

I think it could also be helpful a constructor for JarClassLoader that receives a parent class loader, for example to do something like this.

jcl = new JarClassLoader(new SecureClassLoader() {
      @Override
      protected PermissionCollection getPermissions(CodeSource codesource) {
        PermissionCollection pcol = super.getPermissions(codesource);
        pcol.add(new AllPermission());
        return (pcol);
      }
  });

The last one, I don't implement it yet, but is a public Enumeration<URL> getResources(String name) throws IOException method for each of the ProxyClassLoader implementations. I think the implementations could be something like:

  • SystemLoader
public Enumeration<URL> getResources(String name) throws IOException 
{
    return getSystemResources(name);
}
  • ParentLoader
public Enumeration<URL> getResources(String name) throws IOException 
{
     return getParent().getResources(name);
}
  • CurrentLoader
public Enumeration<URL> getResources(String name) throws IOException 
{
    return getClass().getClassLoader().getResources(name);
}
  • ThreadContextLoader
public Enumeration<URL> getResources(String name) throws IOException 
{
    return Thread.currentThread().getContextClassLoader().getResources(name);
}

Tell me what you think about them as I can learn from your knowledge in classloading!!!

Auto-proxying does not recursively search for all interfaces

Auto-proxying does not recursively search for interfaces, so this small example unexpectedly does not work:

interface I {}
class A implements I{}
class B extends A {}
JarClassLoader jcl = new JarClassLoader();
JclObjectFactory factory = JclObjectFactory.getInstance(true);
Object o = factory.create(jcl, "B");

Results in:

Exception in thread "main" org.xeustechnologies.jcl.exception.JclException: org.xeustechnologies.jcl.exception.JclException: Neither the class [B] nor all the implemented interfaces found in the current classloader
	at org.xeustechnologies.jcl.JclObjectFactory.create(JclObjectFactory.java:93)

The fix would be to change JclObjectFactory.java with:

//            Class[] interfaces = object.getClass().getInterfaces(); // Remove this line
            List<Class> il = new ArrayList<Class>();


// Use this util e.g. from org.apache.commons:commons-lang3 instead
            List<Class<?>> interfaces = ClassUtils.getAllInterfaces(object.getClass());

Test failure on mvn clean install


T E S T S

Running org.xeustechnologies.jcl.LoadTest
Tests run: 14, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.403 sec <<< F
AILURE!
testDefaultContextLoader(org.xeustechnologies.jcl.LoadTest) Time elapsed: 0.006
sec <<< FAILURE!
junit.framework.AssertionFailedError: Expected JclContextException
at org.xeustechnologies.jcl.LoadTest.testDefaultContextLoader(LoadTest.j
ava:246)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:57)

Enabling Thread Loader causes stack overflow with spring

Caused by: java.lang.StackOverflowError at java.io.UnixFileSystem.getBooleanAttributes0(Native Method) at java.io.UnixFileSystem.getBooleanAttributes(UnixFileSystem.java:242) at java.io.File.exists(File.java:772) at sun.misc.URLClassPath$FileLoader.getResource(URLClassPath.java:1072) at sun.misc.URLClassPath$FileLoader.findResource(URLClassPath.java:1039) at sun.misc.URLClassPath.findResource(URLClassPath.java:176) at java.net.URLClassLoader$2.run(URLClassLoader.java:551) at java.net.URLClassLoader$2.run(URLClassLoader.java:549) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findResource(URLClassLoader.java:548) at java.lang.ClassLoader.getResource(ClassLoader.java:1139) at java.net.URLClassLoader.getResourceAsStream(URLClassLoader.java:227) at org.xeustechnologies.jcl.AbstractClassLoader$CurrentLoader.loadResource(AbstractClassLoader.java:286) at org.xeustechnologies.jcl.AbstractClassLoader.getResourceAsStream(AbstractClassLoader.java:158) at org.xeustechnologies.jcl.AbstractClassLoader$ThreadContextLoader.loadResource(AbstractClassLoader.java:329) at org.xeustechnologies.jcl.AbstractClassLoader.getResourceAsStream(AbstractClassLoader.java:158) at org.xeustechnologies.jcl.AbstractClassLoader$ThreadContextLoader.loadResource(AbstractClassLoader.java:329) at org.xeustechnologies.jcl.AbstractClassLoader.getResourceAsStream(AbstractClassLoader.java:158) at org.xeustechnologies.jcl.AbstractClassLoader$ThreadContextLoader.loadResource(AbstractClassLoader.java:329)

How to fully release/close a loaded jar ?

Hi

I'm looking for a solution to release a loaded jar from the memory.
The following code shows how I tried it so far.
Any better ideas?

thx

`import org.xeustechnologies.jcl.JarClassLoader;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Vector;
import java.util.jar.JarFile;

public class JarLoader extends JarClassLoader{

protected HashSet<String> setJarFileNames2Close = new HashSet<String>();

public void release(){
	close();
	loaders.clear();
	classes.clear();
}

public void close() {
	setJarFileNames2Close.clear();
	closeClassLoader(this);
	finalizeNativeLibs(this);
	cleanupJarFileFactory();
}

/**
 * cleanup jar file factory cache
 */
@SuppressWarnings({ "nls", "unchecked" })
public boolean cleanupJarFileFactory()
{
	boolean res = false;
	Class classJarURLConnection = null;
	try {
		classJarURLConnection = Class.forName("sun.net.www.protocol.jar.JarURLConnection");
	} catch (ClassNotFoundException e) {
		//ignore
	}
	if (classJarURLConnection == null) {
		return res;
	}
	Field f = null;
	try {
		f = classJarURLConnection.getDeclaredField("factory");
	} catch (NoSuchFieldException e) {
		//ignore
	}
	if (f == null) {
		return res;
	}
	f.setAccessible(true);
	Object obj = null;
	try {
		obj = f.get(null);
	} catch (IllegalAccessException e) {
		//ignore
	}
	if (obj == null) {
		return res;
	}
	Class classJarFileFactory = obj.getClass();
	//
	HashMap fileCache = null;
	try {
		f = classJarFileFactory.getDeclaredField("fileCache");
		f.setAccessible(true);
		obj = f.get(null);
		if (obj instanceof HashMap) {
			fileCache = (HashMap)obj;
		}
	} catch (NoSuchFieldException e) {
	} catch (IllegalAccessException e) {
		//ignore
	}
	HashMap urlCache = null;
	try {
		f = classJarFileFactory.getDeclaredField("urlCache");
		f.setAccessible(true);
		obj = f.get(null);
		if (obj instanceof HashMap) {
			urlCache = (HashMap)obj;
		}
	} catch (NoSuchFieldException e) {
	} catch (IllegalAccessException e) {
		//ignore
	}
	if (urlCache != null) {
		HashMap urlCacheTmp = (HashMap)urlCache.clone();
		Iterator it = urlCacheTmp.keySet().iterator();
		while (it.hasNext()) {
			obj = it.next();
			if (!(obj instanceof JarFile)) {
				continue;
			}
			JarFile jarFile = (JarFile)obj;
			if (setJarFileNames2Close.contains(jarFile.getName())) {
				try {
					jarFile.close();
				} catch (IOException e) {
					//ignore
				}
				if (fileCache != null) {
					fileCache.remove(urlCache.get(jarFile));
				}
				urlCache.remove(jarFile);
			}
		}
		res = true;
	} else if (fileCache != null) {
		// urlCache := null
		HashMap fileCacheTmp = (HashMap)fileCache.clone();
		Iterator it = fileCacheTmp.keySet().iterator();
		while (it.hasNext()) {
			Object key = it.next();
			obj = fileCache.get(key);
			if (!(obj instanceof JarFile)) {
				continue;
			}
			JarFile jarFile = (JarFile)obj;
			if (setJarFileNames2Close.contains(jarFile.getName())) {
				try {
					jarFile.close();
				} catch (IOException e) {
					//ignore
				}
				fileCache.remove(key);
			}
		}
		res = true;
	}
	setJarFileNames2Close.clear();
	return res;
}

/**
 * close jar files of cl
 * @param cl
 * @return
 */
@SuppressWarnings( { "nls", "unchecked" })
public boolean closeClassLoader(ClassLoader cl) {
	boolean res = false;
	if (cl == null) {
		return res;
	}
	Class classURLClassLoader = JarLoader.class;
	Field f = null;
	try {
		f = classURLClassLoader.getDeclaredField("ucp");
	} catch (NoSuchFieldException e1) {
		//ignore
	}
	if (f != null) {
		f.setAccessible(true);
		Object obj = null;
		try {
			obj = f.get(cl);
		} catch (IllegalAccessException e1) {
			//ignore
		}
		if (obj != null) {
			final Object ucp = obj;
			f = null;
			try {
				f = ucp.getClass().getDeclaredField("loaders");
			} catch (NoSuchFieldException e1) {
				//ignore
			}
			if (f != null) {
				f.setAccessible(true);
				ArrayList loaders = null;
				try {
					loaders = (ArrayList) f.get(ucp);
					res = true;
				} catch (IllegalAccessException e1) {
					//ignore
				}
				for (int i = 0; loaders != null && i < loaders.size(); i++) {
					obj = loaders.get(i);
					f = null;
					try {
						f = obj.getClass().getDeclaredField("jar");
					} catch (NoSuchFieldException e) {
						//ignore
					}
					if (f != null) {
						f.setAccessible(true);
						try {
							obj = f.get(obj);
						} catch (IllegalAccessException e1) {
							// ignore
						}
						if (obj instanceof JarFile) {
							final JarFile jarFile = (JarFile)obj;
							setJarFileNames2Close.add(jarFile.getName());
							//try {
							//	jarFile.getManifest().clear();
							//} catch (IOException e) {
							//	// ignore
							//}
							try {
								jarFile.close();
							} catch (IOException e) {
								// ignore
							}
						}
					}
				}
			}
		}
	}
	return res;
}

/**
 * finalize native libraries
 * @param cl
 * @return
 */
@SuppressWarnings({ "nls", "unchecked" })
public boolean finalizeNativeLibs(ClassLoader cl) {
	boolean res = false;
	Class classClassLoader = ClassLoader.class;
	java.lang.reflect.Field nativeLibraries = null;
	try {
		nativeLibraries = classClassLoader.getDeclaredField("nativeLibraries");
	} catch (NoSuchFieldException e1) {
		//ignore
	}
	if (nativeLibraries == null) {
		return res;
	}
	nativeLibraries.setAccessible(true);
	Object obj = null;
	try {
		obj = nativeLibraries.get(cl);
	} catch (IllegalAccessException e1) {
		//ignore
	}
	if (!(obj instanceof Vector)) {
		return res;
	}
	res = true;
	Vector java_lang_ClassLoader_NativeLibrary = (Vector)obj;
	for (Object lib : java_lang_ClassLoader_NativeLibrary) {
		java.lang.reflect.Method finalize = null;
		try {
			finalize = lib.getClass().getDeclaredMethod("finalize", new Class[0]);
		} catch (NoSuchMethodException e) {
			//ignore
		}
		if (finalize != null) {
			finalize.setAccessible(true);
			try {
				finalize.invoke(lib, new Object[0]);
			} catch (IllegalAccessException e) {
			} catch (InvocationTargetException e) {
				//ignore
			}
		}
	}
	return res;
}

}
`

Integration Tutorial

Hi,

this looks very interesting, but my programming skills aren't good enough to understand how to use this library from reading the existing documentation.
It would be great if you could write a tutorial on how use this with Spring with minimal added code. (i.e. without explicitly accessing jcl all the time).

Tagging the releases

Would it be possible to tag the commits that correspond to a release (for example v2.3, ...)?

With Java8

Hi,

We have been using this for a while and always thank you !

We tested our code with Java 8 and found an exception, which was never seen before.

Caused by: java.util.ConcurrentModificationException: null

    at java.util.ArrayList.sort(ArrayList.java:1456) ~[na:1.8.0_31]

    at java.util.Collections.sort(Collections.java:141) ~[na:1.8.0_31]

    at org.xeustechnologies.jcl.AbstractClassLoader.loadClass(AbstractClassLoader.java:97) ~[ebinocle-indexer-25.9-jar-with-dependencies.jar:25.9]

    at org.xeustechnologies.jcl.AbstractClassLoader.loadClass(AbstractClassLoader.java:82) ~[ebinocle-indexer-25.9-jar-with-dependencies.jar:25.9]

    at org.xeustechnologies.jcl.JclObjectFactory.create(JclObjectFactory.java:95) ~[ebinocle-indexer-25.9-jar-with-dependencies.jar:25.9]

In Java8, Collections.sort is implemented differently from the previous Java.

Someone had a similar issue and wrote about it here:
http://onelineatatime.io/collections-sort-the-java8u20-modification/

I had a look at the relevant code.
Moving 'Collections.sort' into methods modifying the list (addDefaultLoader & addLoader) can be a simple solution but I am unsure if it is okay enough.

I would appreciate it if you have a look at this issue.

Regards,
Youngmi.

New SPI issues in 1.7

I originally posted this under the closed #32 but it should live in its own issue since it's a different but related bug.

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)

Support for directory entries from jar files

It would be great if JCL had an ability to load not only the files from .jar, but also the directories. It is now not supported, since there's a line in JarResources class:

                if (jarEntry.isDirectory()) {
                    continue;
                }

Without that ability it's impossible to scan the classpath for the files within directories and use the tools like PathMatchingResourcePatternResolver (from Spring), which is working great with the standard URLClassLoader.

2.8 Release

Are there plans on a 2.8 release? Is this project still active?

getResource() fails for resources that are not within a jar

Say you have a directory structure like this:

    someDirectory/
           someFile

You can have jars or classes inside someDirectory too, it doesn't matter.
If you call:

    jcl.add("someDirectory")

And then try to call jcl.getResource("someFile"), JCL throws an exception:

    org.xeustechnologies.jcl.exception.JclException: java.net.MalformedURLException: no protocol: /home/whoever/file/path/someDirectory/someFilesomeFile
    at org.xeustechnologies.jcl.JarResources.getResourceURL(JarResources.java:74)
    at org.xeustechnologies.jcl.JarClassLoader$LocalLoader.findResource(JarClassLoader.java:285)
    at org.xeustechnologies.jcl.AbstractClassLoader.getResource(AbstractClassLoader.java:150)

Note that the filename (someFile) is actually repeated twice in the returned filename.
I'll submit a PR shortly.

JMS client is not working when initial context factory is loaded using JCL class loader

I'm trying to implement a JMS client using Weblogic implementation, but its not working correctly.
The inicial context factory class of Weblogic JMS implementation is weblogic.jndi.WLInitialContextFactory.
I was looking at the code and I found the reason it was not working. The class mentioned above is found by JCL, but for some reason, JCL is creating the instance in a different way of the class loader used by JMS, the context class loader.

// JMS is instantiating the initial context factory this way:
loadClass(className, getContextClassLoader())

// The code above call...
Class.forName(className, true, classLoader)

// Getting class loader:
ClassLoader getContextClassLoader() {
  return AccessController.doPrivileged(
    new PrivilegedAction<ClassLoader>() {
      public ClassLoader run() {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        if (loader == null) {
          // Don't use bootstrap class loader directly!
          loader = ClassLoader.getSystemClassLoader();
        }
        return loader;
      }
    }
  );
}

Loading the initial context factory class using Thread.currentThread().getContextClassLoader() works fine. Using JCL class loader, the class is instantiated, but for some reason I could not connect to JMS server.

Set ProtectionDomain/CodeSource

Some code as equinox for example makes all sort of usage of ProtectionDomain/CodeSource.
So, can you please set those while defining classes? I know it cannot be done in all cases but at least for loading a jar from an URL it can be done.
Take for example how to do it http://www.docjar.com/html/api/java/security/SecureClassLoader.java.html

Maybe even think on having an addition optional param on add() for specifing the code source url.

BTW, why not using github? is such an easier and better way to contribute. I could have done that and only asked you to pull.

Can't download JCL dependency using Ivy/Ant.

I attempted to include the JCL library using Ivy/Ant, with the following include:

The Ivy portion of the build doesn't complain, but it also doesn't download any jar files. Looking at the Maven repos, JCL seems to be missing some references (ie there are no jar files references, and no source code either). Apologies if I'm missing something, I'm not a Maven expert. Does including JCL in a Maven project work as expected?

Don't close InputStream

Currently if you add InputStream to jcl instance, it will close it.
This is due to the use of a BufferedInputStream which on close, close underlying inputstream.
This is damageable when you use a ZipInputStream which contains many different jars which has to be loaded into jcl.
Jcl should not close resources give to it.
Bypass is to pass a new instance of an InputStream on each ZipEntry which match jar file.

Problematic code:
`
public static void loadJars(final InputStream stream) throws IOException {

final JarClassLoader jcl = new JarClassLoader();
try (ZipInputStream zip = new ZipInputStream(stream)) {
    ZipEntry entry;
    while ((entry = zip.getNextEntry()) != null) {
    final String name = entry.getName();
    if (name.matches(".*\\.jar")) {
        jcl.add(zip);
    }
    }
}

}`

There isn't any support of getPackage() method

I loaded dynamically JDBC driver jar and called acceptsURL method (with MethodHandle): as I got a NPE with MySQL Driver, I read the MySQL code and noticed the NPE occurs because of invoking method getPackage() (in com.mysql.jdbc.Util), that always returns a null reference.

java.lang.LinkageError

  @Test
  public void test() throws Exception {
JarClassLoader jcl = new JarClassLoader();

//adding Test.jar (consist of com.google.at.mortezaadi.Sample)
//to JCL
jcl.add("test/Test.jar");

// insuring JCL can load the class
Class loadedClass = jcl.loadClass(
    "com.google.at.mortezaadi.Sample");
assertNotNull(loadedClass);

// unload class file inside the Test.Jar
jcl.unloadClass("com.google.at.mortezaadi.Sample");

// insuring jcl unloaded the class
boolean classExsist = false;
try{
    jcl.loadClass("com.google.at.mortezaadi.Sample");
    classExsist = true;
}catch(Exception ex) {
}
assertTrue(!classExsist);

/******************************/
//adding jar file again  
jcl.add("test/Test.jar");

   /** loading file again THROWS EXCEPTION
 * java.lang.LinkageError: loader (instance of  org/xeustechnologies/jcl/JarClassLoader): attempted  duplicate    class definition for name: "com/google/at/mortezaadi/Sample"
 */
loadedClass = jcl.loadClass(
    "com.google.at.mortezaadi.Sample");
}

getResources() does not return all resources in all jars of a given classloader

I'm using JCL in a simple manner, I think. I create a classloader and add() a bunch of jars.

Some of these jars have identically named resources. From this class loader I try getResources() expecting the enumeration to find all the resources. Unfortunately, I only get the first resource.

I debugged the code and it seems that every classloader only returns one resource through findResource(), I think..

Am I doing something really wrong ?

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

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?

getResourceAsStream shouldn't throw Exception?

Great work on this. I'm using it to create an isolated container for running scheduled tasks.

However, I found an issue when using the JarClassLoader to load a spring configuration file.
During the rather convoluted jaxp/xerces validation sequence that occurs at one point the xerces code attempts to load a configuration setting which may or may not exist 'META-INF/services/org.apache.xerces.xni.parser.XMLParserConfiguration'.

The calling xerces code is not expecting an exception to be thrown if the resource does not exist rather it is simply checking for a null value to be returned. Due to the exception the whole sequence fails etc.

I was able to get around it by subclassing the JarClassLoader and simply overriding the getResourceAsStream method to swallow the exception and throw null. But it took some time to figure out this is what was causing the issue.

You may want to consider not throwing the exception so it is more consistent with the standard ClassLoader.( The current java 6 ClassLoader also does not throw an exception but simply returns null).
Thanks.

Heap space

Hi, I've this error after some times my class try to load an external jar file.

java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3230)
at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:113)
at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:140)
at org.xeustechnologies.jcl.JarResources.loadJar(JarResources.java:201)
at org.xeustechnologies.jcl.JarResources.loadJar(JarResources.java:119)
at org.xeustechnologies.jcl.ClasspathResources.loadResource(ClasspathResources.java:262)
at org.xeustechnologies.jcl.ClasspathResources.loadResource(ClasspathResources.java:285)
at org.xeustechnologies.jcl.ClasspathResources.loadResource(ClasspathResources.java:285)
at org.xeustechnologies.jcl.ClasspathResources.loadResource(ClasspathResources.java:285)
at org.xeustechnologies.jcl.ClasspathResources.loadResource(ClasspathResources.java:285)
at org.xeustechnologies.jcl.ClasspathResources.loadResource(ClasspathResources.java:285)
at org.xeustechnologies.jcl.ClasspathResources.loadResource(ClasspathResources.java:246)
at org.xeustechnologies.jcl.JarClassLoader.add(JarClassLoader.java:141)

Cannot load class which is presented in JAR

Hi!

I'm trying to do this

jcl.loadClass("com.bea.xml.stream.MXParserFactory");

But getting ClassNotFound exception. This class is presented in JAR - I can see it in archive. What's wrong with my code?

Suggestion

Is there a possibility to retrieve the Class object without instantiate the Object :

Here's an example
`
JarClassLoader jcl = new JarClassLoader();
JclObjectFactory factory = JclObjectFactory.getInstance();
Class<?> clazz = factory.classOf(jcl,"com.myclass");

`
Thanks in advance

Required Package Name

This might not be an issue, but I think it requires documentation. JCL2 requires a package name for loading classes whereas it wasn't required in the original JCL. Code at line 64 in JarClassLoader.java breaks when the class being loaded is not part of a package.

How to use JCL with JavaConfig in Spring Boot

Hi I am trying to use JCL with an application developed with Spring Boot. Is it possible to integrate an object created with JCL in Spring Boot context? Your documentation uses an xml, is it possible to integrate the object created with JCL with JavaConfig?

Thanks in advance.
Regards,
Giuseppe

load jar from jar Manifest

Hi,

Great library !!! 👍
I've a suggestion for this project : add JAR cascade loading support (by using MANIFEST.MF).

// Some possible snippet :
JarClassLoader jcl = new JarClassLoader();

//Loading classes from different sources
// true to allow JCL to load jar defined in manifest
jcl.add("myjar.jar", true);

Which License?

I was looking at using this library and wanted to understand the licensing. The code itself appears to be marked with Apache 2.0, but the
JCL/JCL2/core/src/main/resources/LICENSE.txt and
JCL2/pom.xml
both indicate GNU LGPL

Could you let me know which it is? I'm happy to put together a PR for full conversion to Apache 2.0, which I'd need to incorporate this into my project.

Thanks
Donald

ClassCast exception even when using JclUtils.cast()

Thank you so much for making JCL available to us, it is a real lifesaver for my project!

I'm trying to implement dynamic loading of alert plugins for my babysitter monitor service:
https://github.com/massenz/babysitter
(relevant classes are in the com.rivermeadow.babysitter.alerts package)

In the final version, the JAR would uploaded via a POST specifying the main class implementing the plugin API.

To simplifiy a bit, an AlertPlugin implements the lifecycle methods, with the activate() method returning a Pager class, which will actually respond to the alerts.

However, when I try to implement the dynamic loading using JCL (loaded via Maven, jcl-core, version 2.5) it does work by getting me a valid AlertPlugin class, but I get a ClassCastException when I try to load the Pager via the activate() method, even if I use JclUtils.cast().

If I modify the API to return me the name of the class implementing the Pager interface, and load that one via JCL then it all works just fine: so I guess I have a workaround, but I'm wondering what am I doing wrong, of if it's a genuine bug.

BTW, using ObjectFactory.getInstance(true) doesn't work at all.

See an example here:
https://gist.github.com/massenz/7402453

More than happy to contribute to the project, if I can help implementing this.

Is it work for JCL to load a jar with his dependen jars?

Is it work for JCL to load a jar with his dependen jars? Can you give an example if this is true? Prefer such example in /test. Thanks.

The background is I use JCL to avoid httpclient version conflicts. My jar depends on Rest-Assured jar, and Rest-Assured depends httpclient jar. Can I use JCL to load all 3 jars, so I can avoid confilicts?

How to install?

mvn clean install
[INFO] Scanning for projects...
Downloading: https://repo.maven.apache.org/maven2/org/sonatype/oss/oss-parent/5/
oss-parent-5.pom
[ERROR] The build could not read 1 project -> [Help 1]
[ERROR]
[ERROR] The project org.xeustechnologies:jcl:2.5 (C:\Users\I302583\Downloads\J
CL-jcl-2.5\JCL2\pom.xml) has 1 error
[ERROR] Non-resolvable parent POM: Could not transfer artifact org.sonatype.
oss:oss-parent:pom:5 from/to central (https://repo.maven.apache.org/maven2): rep
o.maven.apache.org and 'parent.relativePath' points at wrong local POM @ line 13
, column 10: Unknown host repo.maven.apache.org -> [Help 2]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e swit
ch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please rea
d the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectBuildin
gException
[ERROR] [Help 2] http://cwiki.apache.org/confluence/display/MAVEN/UnresolvableMo
delException

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.