diff --git a/core/src/main/java/org/jruby/RubyClass.java b/core/src/main/java/org/jruby/RubyClass.java index e3a77e2db9c..ad305373d58 100644 --- a/core/src/main/java/org/jruby/RubyClass.java +++ b/core/src/main/java/org/jruby/RubyClass.java @@ -60,6 +60,7 @@ import org.jruby.compiler.impl.SkinnyMethodAdapter; import org.jruby.exceptions.RaiseException; import org.jruby.internal.runtime.methods.DynamicMethod; +import org.jruby.java.codegen.MultiClassLoader; import org.jruby.java.codegen.RealClassGenerator; import org.jruby.java.codegen.Reified; import org.jruby.java.proxies.ConcreteJavaProxy; @@ -90,6 +91,7 @@ import org.jruby.util.ClassDefiningClassLoader; import org.jruby.util.CodegenUtils; import org.jruby.util.JavaNameMangler; +import org.jruby.util.Loader; import org.jruby.util.OneShotClassLoader; import org.jruby.util.StringSupport; import org.jruby.util.collections.ConcurrentWeakHashMap; @@ -1357,7 +1359,11 @@ public synchronized void reify(String classDumpDir, boolean useChildLoader) { parentCL = (OneShotClassLoader) parentReified.getClassLoader(); } else { if (useChildLoader) { - parentCL = new OneShotClassLoader(runtime.getJRubyClassLoader()); + MultiClassLoader parentLoader = new MultiClassLoader(runtime.getJRubyClassLoader()); + for(Loader cLoader : runtime.getInstanceConfig().getExtraLoaders()) { + parentLoader.addClassLoader(cLoader.getClassLoader()); + } + parentCL = new OneShotClassLoader(parentLoader); } else { parentCL = runtime.getJRubyClassLoader(); } diff --git a/rakelib/test.rake b/rakelib/test.rake index 7c75cb8c243..fd6c7b2f4a5 100644 --- a/rakelib/test.rake +++ b/rakelib/test.rake @@ -25,11 +25,21 @@ namespace :test do desc "Compile test code" task :compile do mkdir_p "test/target/test-classes" + mkdir_p "test/target/test-classes-isolated/java_integration/fixtures/isolated" + mkdir_p "test/target/test-interfaces-isolated/java_integration/fixtures/isolated" + classpath = %w[lib/jruby.jar test/target/junit.jar test/target/annotation-api.jar].join(File::PATH_SEPARATOR) # try detecting javac - so we use the same Java versions as we're running (JAVA_HOME) with : java_home = [ ENV_JAVA['java.home'], File.join(ENV_JAVA['java.home'], '..') ] # in case of jdk/jre javac = java_home.map { |home| File.expand_path('bin/javac', home) }.find { |javac| File.exist?(javac) } || 'javac' sh "#{javac} -cp #{classpath} -d test/target/test-classes #{Dir['spec/java_integration/fixtures/**/*.java'].to_a.join(' ')}" + # move the objects that need to be in separate class loaders + mv "test/target/test-classes/java_integration/fixtures/isolated/classes", + "test/target/test-classes-isolated/java_integration/fixtures/isolated", + force: true + mv "test/target/test-classes/java_integration/fixtures/isolated/interfaces", + "test/target/test-interfaces-isolated/java_integration/fixtures/isolated", + force: true end short_tests = ['jruby', 'mri'] diff --git a/spec/java_integration/fixtures/isolated/classes/GH7327Base.java b/spec/java_integration/fixtures/isolated/classes/GH7327Base.java new file mode 100644 index 00000000000..cb158cd3fb8 --- /dev/null +++ b/spec/java_integration/fixtures/isolated/classes/GH7327Base.java @@ -0,0 +1,4 @@ +package java_integration.fixtures.isolated.classes; + +public class GH7327Base { +} diff --git a/spec/java_integration/fixtures/isolated/interfaces/GH7327Interface.java b/spec/java_integration/fixtures/isolated/interfaces/GH7327Interface.java new file mode 100644 index 00000000000..3055f3b3862 --- /dev/null +++ b/spec/java_integration/fixtures/isolated/interfaces/GH7327Interface.java @@ -0,0 +1,4 @@ +package java_integration.fixtures.isolated.interfaces; + +public interface GH7327Interface { +} diff --git a/spec/java_integration/reify/become_java_spec.rb b/spec/java_integration/reify/become_java_spec.rb index 93c6cd1b9dc..7ea296c4374 100644 --- a/spec/java_integration/reify/become_java_spec.rb +++ b/spec/java_integration/reify/become_java_spec.rb @@ -341,6 +341,37 @@ class JRUBY5564; end expect(klass.load_class(a_class.get_name)).to eq(a_class) end + it "supports reifying concrete classes extending classes from an unrelated class loader" do + isolated_class_path = File.expand_path('../../../../test/target/test-classes-isolated', __FILE__) + classloader = java.net.URLClassLoader.new([java.net.URL.new("file://#{isolated_class_path}/")].to_java(java.net.URL)) + JRuby.runtime.instance_config.add_loader(classloader) + + # we can reference it from JRuby, because it was added to the JRuby loader above + class GH7327 < Java::Java_integrationFixturesIsolatedClasses::GH7327Base; end + # it should have created a unique Java class + expect(GH7327.become_java!).not_to eq(Java::Java_integrationFixturesIsolatedClasses::GH7327Base.java_class) + ensure + JRuby.runtime.instance_config.extra_loaders.clear + end + + it "supports reifying concrete classes extending classes and implementing interfaces from multiple unrelated class loaders" do + isolated_class_path = File.expand_path('../../../../test/target/test-classes-isolated', __FILE__) + classloader1 = java.net.URLClassLoader.new([java.net.URL.new("file://#{isolated_class_path}/")].to_java(java.net.URL)) + JRuby.runtime.instance_config.add_loader(classloader1) + isolated_interface_path = File.expand_path('../../../../test/target/test-interfaces-isolated', __FILE__) + classloader2 = java.net.URLClassLoader.new([java.net.URL.new("file://#{isolated_interface_path}/")].to_java(java.net.URL)) + JRuby.runtime.instance_config.add_loader(classloader2) + + # we can reference them from JRuby, because they were added to the JRuby loader above + class GH7327WithInterface < Java::Java_integrationFixturesIsolatedClasses::GH7327Base + include Java::Java_integrationFixturesIsolatedInterfaces::GH7327Interface + end + # it should have created a unique Java class + expect(GH7327WithInterface.become_java!).not_to eq(Java::Java_integrationFixturesIsolatedClasses::GH7327Base.java_class) + ensure + JRuby.runtime.instance_config.extra_loaders.clear + end + class ReifiedSample def hello; 'Sayonara from Ruby' end java_signature "java.lang.String ahoy()"