diff --git a/core/src/main/java/org/jruby/Ruby.java b/core/src/main/java/org/jruby/Ruby.java
index 647cf199387..6ec1c10242f 100644
--- a/core/src/main/java/org/jruby/Ruby.java
+++ b/core/src/main/java/org/jruby/Ruby.java
@@ -141,6 +141,7 @@
import org.jruby.util.ByteList;
import org.jruby.util.DefinedMessage;
import org.jruby.util.JRubyClassLoader;
+import org.jruby.util.SelfFirstJRubyClassLoader;
import org.jruby.util.IOInputStream;
import org.jruby.util.IOOutputStream;
import org.jruby.util.ClassDefininngJRubyClassLoader;
@@ -2582,7 +2583,12 @@ public static ClassLoader getClassLoader() {
public synchronized JRubyClassLoader getJRubyClassLoader() {
// FIXME: Get rid of laziness and handle restricted access elsewhere
if (!Ruby.isSecurityRestricted() && jrubyClassLoader == null) {
- jrubyClassLoader = new JRubyClassLoader(config.getLoader());
+ if (config.isSelfFirstClassLoader()){
+ jrubyClassLoader = new SelfFirstJRubyClassLoader(config.getLoader());
+ }
+ else {
+ jrubyClassLoader = new JRubyClassLoader(config.getLoader());
+ }
// if jit code cache is used, we need to add the cache directory to the classpath
// so the previously generated class files can be reused.
diff --git a/core/src/main/java/org/jruby/RubyInstanceConfig.java b/core/src/main/java/org/jruby/RubyInstanceConfig.java
index e28d12dea53..6ebf793d4e7 100644
--- a/core/src/main/java/org/jruby/RubyInstanceConfig.java
+++ b/core/src/main/java/org/jruby/RubyInstanceConfig.java
@@ -1227,6 +1227,28 @@ public boolean isNativeEnabled() {
return _nativeEnabled;
}
+ /**
+ * Set whether to use the self-first jruby classloader.
+ *
+ * @see Options#SELF_FIRST_CLASS_LOADER
+ *
+ * @param b new value indicating whether self-first classloader is used
+ */
+ public void setSelfFirstClassLoader(boolean b) {
+ _selfFirstClassLoader = b;
+ }
+
+ /**
+ * Get whether to use the self-first jruby classloader.
+ *
+ * @see Options#SELF_FIRST_CLASS_LOADER
+ *
+ * @return true if self-first classloader is used; false otherwise.
+ */
+ public boolean isSelfFirstClassLoader() {
+ return _selfFirstClassLoader;
+ }
+
/**
* @see Options#CLI_STRIP_HEADER
*/
@@ -1472,6 +1494,7 @@ public void setProfilingService( String service ) {
* Whether native code is enabled for this configuration.
*/
private boolean _nativeEnabled = NATIVE_ENABLED;
+ private boolean _selfFirstClassLoader = SELF_FIRST_CLASS_LOADER;
private TraceType traceType =
TraceType.traceTypeFor(Options.BACKTRACE_STYLE.load());
@@ -1674,6 +1697,7 @@ public boolean shouldPrecompileAll() {
* Set with the jruby.native.enabled system property.
*/
public static final boolean NATIVE_ENABLED = Options.NATIVE_ENABLED.load();
+ public static final boolean SELF_FIRST_CLASS_LOADER = Options.SELF_FIRST_CLASS_LOADER.load();
@Deprecated
public final static boolean CEXT_ENABLED = false;
diff --git a/core/src/main/java/org/jruby/util/JRubyClassLoader.java b/core/src/main/java/org/jruby/util/JRubyClassLoader.java
index 0db783dae69..2d5e0b5f230 100644
--- a/core/src/main/java/org/jruby/util/JRubyClassLoader.java
+++ b/core/src/main/java/org/jruby/util/JRubyClassLoader.java
@@ -120,28 +120,6 @@ public void addURL(URL url) {
indexJarContents(url);
}
- @Override
- public Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- synchronized (getClassLoadingLock(name)) {
- Class> c = findLoadedClass(name);
- if (c == null) {
- try {
- c = findClass(name);
- } catch (ClassNotFoundException e) {
- return super.loadClass(name, resolve);
- }
- }
- return c;
- }
- }
- public URL getResource( String name ) {
- URL resource = findResource(name);
- if (resource == null) {
- resource = super.getResource(name);
- }
- return resource;
- }
-
/**
* Called when the parent runtime is torn down.
*/
diff --git a/core/src/main/java/org/jruby/util/SelfFirstJRubyClassLoader.java b/core/src/main/java/org/jruby/util/SelfFirstJRubyClassLoader.java
new file mode 100644
index 00000000000..03727c8d124
--- /dev/null
+++ b/core/src/main/java/org/jruby/util/SelfFirstJRubyClassLoader.java
@@ -0,0 +1,61 @@
+/*
+ **** BEGIN LICENSE BLOCK *****
+ * Version: EPL 1.0/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Eclipse Public
+ * License Version 1.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the EPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the EPL, the GPL or the LGPL.
+ ***** END LICENSE BLOCK *****/
+
+package org.jruby.util;
+
+import java.net.URL;
+
+public class SelfFirstJRubyClassLoader extends JRubyClassLoader {
+
+ public SelfFirstJRubyClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ @Override
+ public Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ synchronized (getClassLoadingLock(name)) {
+ Class> c = findLoadedClass(name);
+ if (c == null) {
+ try {
+ c = findClass(name);
+ } catch (ClassNotFoundException e) {
+ return super.loadClass(name, resolve);
+ }
+ }
+ return c;
+ }
+ }
+
+ @Override
+ public URL getResource( String name ) {
+ URL resource = findResource(name);
+ if (resource == null) {
+ resource = super.getResource(name);
+ }
+ return resource;
+ }
+}
diff --git a/core/src/main/java/org/jruby/util/cli/Options.java b/core/src/main/java/org/jruby/util/cli/Options.java
index 771118d12d1..f1e89b586b6 100644
--- a/core/src/main/java/org/jruby/util/cli/Options.java
+++ b/core/src/main/java/org/jruby/util/cli/Options.java
@@ -169,6 +169,7 @@ public class Options {
public static final Option THREADPOOL_TTL = integer(THREADPOOL, "thread.pool.ttl", 60, "The maximum number of seconds to keep alive an idle thread.");
public static final Option FIBER_THREADPOOL_TTL = integer(THREADPOOL, "fiber.thread.pool.ttl", 60, "The maximum number of seconds to keep alive a pooled fiber thread.");
+ public static final Option SELF_FIRST_CLASS_LOADER = bool(MISCELLANEOUS, "self.first.class.loader", false, "Uses a self-first classloading strategy which might help in some cases of classloader conflicts.");
public static final Option OBJECTSPACE_ENABLED = bool(MISCELLANEOUS, "objectspace.enabled", false, "Enable or disable ObjectSpace.each_object.");
public static final Option SIPHASH_ENABLED = bool(MISCELLANEOUS, "siphash.enabled", false, "Enable or disable SipHash for String hash function.");
public static final Option LAUNCH_INPROC = bool(MISCELLANEOUS, "launch.inproc", false, "Set in-process launching of e.g. system('ruby ...').");
diff --git a/maven/jruby-complete/src/it/bouncycastle-with-bc-gem/src/test/java/org/jruby/its/BouncyCastleTestCase.java b/maven/jruby-complete/src/it/bouncycastle-with-bc-gem/src/test/java/org/jruby/its/BouncyCastleTestCase.java
index d78ff65e582..e25c9cd3c47 100644
--- a/maven/jruby-complete/src/it/bouncycastle-with-bc-gem/src/test/java/org/jruby/its/BouncyCastleTestCase.java
+++ b/maven/jruby-complete/src/it/bouncycastle-with-bc-gem/src/test/java/org/jruby/its/BouncyCastleTestCase.java
@@ -22,8 +22,12 @@ public void java(){
@Test
public void ruby(){
+ System.setProperty( "jruby.self.first.class.loader", "true" );
ScriptingContainer container = new ScriptingContainer();
Object result = container.parse( "gem 'bouncy-castle-java', '1.5.0146.1'; require 'bouncy-castle-java'; Java::OrgBouncycastleJceProvider::BouncyCastleProvider.new.info").run();
assertEquals( "BouncyCastle Security Provider v1.46", result.toString() );
+
+ result = container.parse( "JRuby.runtime.jruby_class_loader").run();
+ assertEquals( "org.jruby.util.SelfFirstJRubyClassLoader", result.toString().replaceFirst( "@.*$", "" ) );
}
}
diff --git a/maven/jruby-complete/src/it/bouncycastle/pom.xml b/maven/jruby-complete/src/it/bouncycastle/pom.xml
index 9fc13322869..52a6f5a3c5e 100644
--- a/maven/jruby-complete/src/it/bouncycastle/pom.xml
+++ b/maven/jruby-complete/src/it/bouncycastle/pom.xml
@@ -33,7 +33,7 @@
UTF-8
- 1.49
+ 1.47
diff --git a/maven/jruby-complete/src/it/bouncycastle/src/test/java/org/jruby/its/BouncyCastleTestCase.java b/maven/jruby-complete/src/it/bouncycastle/src/test/java/org/jruby/its/BouncyCastleTestCase.java
index 5fe8cca0b8a..05d883d27d8 100644
--- a/maven/jruby-complete/src/it/bouncycastle/src/test/java/org/jruby/its/BouncyCastleTestCase.java
+++ b/maven/jruby-complete/src/it/bouncycastle/src/test/java/org/jruby/its/BouncyCastleTestCase.java
@@ -10,13 +10,17 @@
public class BouncyCastleTestCase {
@Test
public void java(){
- assertEquals( "BouncyCastle Security Provider v1.49", new BouncyCastleProvider().getInfo() );
+ assertEquals( "BouncyCastle Security Provider v1.47", new BouncyCastleProvider().getInfo() );
}
@Test
public void ruby(){
+ System.setProperty( "jruby.self.first.class.loader", "true" );
ScriptingContainer container = new ScriptingContainer();
Object result = container.parse( "require 'openssl'; Java::OrgBouncycastleJceProvider::BouncyCastleProvider.new.info").run();
- assertEquals( "BouncyCastle Security Provider v1.47", result.toString() );
+ assertEquals( "BouncyCastle Security Provider v1.49", result.toString() );
+
+ result = container.parse( "JRuby.runtime.jruby_class_loader").run();
+ assertEquals( "org.jruby.util.SelfFirstJRubyClassLoader", result.toString().replaceFirst( "@.*$", "" ) );
}
}
diff --git a/maven/jruby/src/it/bouncycastle-with-bc-gem/src/test/java/org/jruby/its/BouncyCastleTestCase.java b/maven/jruby/src/it/bouncycastle-with-bc-gem/src/test/java/org/jruby/its/BouncyCastleTestCase.java
index 752212366a1..85e355b59c3 100644
--- a/maven/jruby/src/it/bouncycastle-with-bc-gem/src/test/java/org/jruby/its/BouncyCastleTestCase.java
+++ b/maven/jruby/src/it/bouncycastle-with-bc-gem/src/test/java/org/jruby/its/BouncyCastleTestCase.java
@@ -22,8 +22,12 @@ public void java(){
@Test
public void ruby(){
+ System.setProperty( "jruby.self.first.class.loader", "true" );
ScriptingContainer container = new ScriptingContainer();
- Object result = container.parse( "gem 'bouncy-castle-java'; require 'bouncy-castle-java'; Java::OrgBouncycastleJceProvider::BouncyCastleProvider.new.info").run();
- assertEquals( "BouncyCastle Security Provider v1.47", result.toString() );
+ Object result = container.parse( "gem 'bouncy-castle-java', '1.5.0146.1'; require 'bouncy-castle-java'; Java::OrgBouncycastleJceProvider::BouncyCastleProvider.new.info").run();
+ assertEquals( "BouncyCastle Security Provider v1.46", result.toString() );
+
+ result = container.parse( "JRuby.runtime.jruby_class_loader").run();
+ assertEquals( "org.jruby.util.SelfFirstJRubyClassLoader", result.toString().replaceFirst( "@.*$", "" ) );
}
}
diff --git a/maven/jruby/src/it/bouncycastle/src/test/java/org/jruby/its/BouncyCastleTestCase.java b/maven/jruby/src/it/bouncycastle/src/test/java/org/jruby/its/BouncyCastleTestCase.java
index 70c6df0f290..f2bcab2b7b1 100644
--- a/maven/jruby/src/it/bouncycastle/src/test/java/org/jruby/its/BouncyCastleTestCase.java
+++ b/maven/jruby/src/it/bouncycastle/src/test/java/org/jruby/its/BouncyCastleTestCase.java
@@ -27,8 +27,12 @@ public void java(){
@Test
public void ruby(){
+ System.setProperty( "jruby.self.first.class.loader", "true" );
ScriptingContainer container = new ScriptingContainer();
Object result = container.parse( "require 'openssl'; Java::OrgBouncycastleJceProvider::BouncyCastleProvider.new.info").run();
assertEquals( "BouncyCastle Security Provider v1.49", result.toString() );
+
+ result = container.parse( "JRuby.runtime.jruby_class_loader").run();
+ assertEquals( "org.jruby.util.SelfFirstJRubyClassLoader", result.toString().replaceFirst( "@.*$", "" ) );
}
}