Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: f3d3fb8d79b9
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: e7ea92d7c39e
Choose a head ref
  • 3 commits
  • 7 files changed
  • 1 contributor

Commits on Sep 17, 2015

  1. Copy the full SHA
    37de51d View commit details
  2. Copy the full SHA
    02efc4d View commit details
  3. [ji] support retrieving (non-public) Java inner classes similar to Ru…

    …by's private constants
    
    fixes #3333
    kares committed Sep 17, 2015
    Copy the full SHA
    e7ea92d View commit details
10 changes: 5 additions & 5 deletions antlib/extra.xml
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-9.0.0.0.rc1.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-9.0.0.0.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>
@@ -136,7 +136,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-9.0.0.0.rc1.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-9.0.0.0.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>
@@ -152,7 +152,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-9.0.0.0.rc1.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-9.0.0.0.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>
@@ -168,7 +168,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-9.0.0.0.rc1.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:lib/jruby.jar:maven/jruby-stdlib/target/jruby-stdlib-9.0.0.0.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>
@@ -460,7 +460,7 @@ build jruby-complete.jar
<env key='GEM_PATH' value='lib/ruby/gems/shared'/>
<arg value='-Djruby.home=uri:classloader://META-INF/jruby.home'/>
<arg value='-cp'/>
<arg value='core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-9.0.0.0.rc1.jar'/>
<arg value='core/target/test-classes:test/target/test-classes:maven/jruby-complete/target/jruby-complete-9.0.0.0.jar'/>
<arg value='org.jruby.Main'/>
<arg value='-I.:test/externals/ruby1.9:test/externals/ruby1.9/ruby'/>
<arg value='-r./test/ruby19_env.rb'/>
21 changes: 13 additions & 8 deletions core/src/main/java/org/jruby/IncludedModuleWrapper.java
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
* Copyright (C) 2005 Charles O Nutter <headius@headius.com>
* Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
* Copyright (C) 2007 William N Dortch <bill.dortch@gmail.com>
*
*
* 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"),
@@ -48,11 +48,11 @@
* other modules. It inserts itself as the immediate superClass of the includer, but defers all
* module methods to the actual superclass. Multiple of these intermediate superclasses can be
* added for multiple included modules.
*
*
* This allows the normal superclass-based searches (searchMethod, getConstant, etc) to traverse
* the superclass ancestors as normal while the included modules do not actually show up in
* direct inheritance traversal.
*
*
* @see org.jruby.RubyModule
*/
public class IncludedModuleWrapper extends IncludedModule {
@@ -65,19 +65,19 @@ public IncludedModuleWrapper(Ruby runtime, RubyClass superClass, RubyModule orig
/**
* Overridden newIncludeClass implementation to allow attaching future includes to the correct module
* (i.e. the one to which this is attached)
*
*
* @see org.jruby.RubyModule#newIncludeClass(RubyClass)
*/
@Override
@Deprecated
public IncludedModuleWrapper newIncludeClass(RubyClass superClass) {
IncludedModuleWrapper includedModule = new IncludedModuleWrapper(getRuntime(), superClass, getNonIncludedClass());

// include its parent (and in turn that module's parents)
if (getSuperClass() != null) {
includedModule.includeModule(getSuperClass());
}

return includedModule;
}

@@ -179,18 +179,23 @@ protected IRubyObject constantTableStore(String name, IRubyObject value) {
return origin.constantTableStore(name, value);
}

protected IRubyObject constantTableStore(String name, IRubyObject value, boolean hidden) {
// FIXME: legal here? may want UnsupportedOperationException
return origin.constantTableStore(name, value, hidden);
}

@Override
protected IRubyObject constantTableRemove(String name) {
// this _is_ legal (when removing an undef)
return origin.constantTableRemove(name);
}

@Override
@Deprecated
public List<String> getStoredConstantNameList() {
return origin.getStoredConstantNameList();
}

@Override
public Collection<String> getConstantNames() {
return origin.getConstantNames();
32 changes: 27 additions & 5 deletions core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
@@ -3570,7 +3570,7 @@ public IRubyObject resolveUndefConstant(String name) {
* @return The result of setting the variable.
*/
public IRubyObject setConstantQuiet(String name, IRubyObject value) {
return setConstantCommon(name, value, false);
return setConstantCommon(name, value, false, false);
}

/**
@@ -3582,7 +3582,11 @@ public IRubyObject setConstantQuiet(String name, IRubyObject value) {
* @return The result of setting the variable.
*/
public IRubyObject setConstant(String name, IRubyObject value) {
return setConstantCommon(name, value, true);
return setConstantCommon(name, value, false, true);
}

public IRubyObject setConstant(String name, IRubyObject value, boolean hidden) {
return setConstantCommon(name, value, hidden, true);
}

/**
@@ -3593,7 +3597,7 @@ public IRubyObject setConstant(String name, IRubyObject value) {
* @param value The value to assign to it; if an unnamed Module, also set its basename to name
* @return The result of setting the variable.
*/
private IRubyObject setConstantCommon(String name, IRubyObject value, boolean warn) {
private IRubyObject setConstantCommon(String name, IRubyObject value, boolean hidden, boolean warn) {
IRubyObject oldValue = fetchConstant(name);
if (oldValue != null) {
if (oldValue == UNDEF) {
@@ -3602,10 +3606,14 @@ private IRubyObject setConstantCommon(String name, IRubyObject value, boolean wa
if (warn) {
getRuntime().getWarnings().warn(ID.CONSTANT_ALREADY_INITIALIZED, "already initialized constant " + name);
}
storeConstant(name, value);
// might just call storeConstant(name, value, hidden) but to maintain
// backwards compatibility with calling #storeConstant overrides
if (hidden) storeConstant(name, value, true);
else storeConstant(name, value);
}
} else {
storeConstant(name, value);
if (hidden) storeConstant(name, value, true);
else storeConstant(name, value);
}

invalidateConstantCache(name);
@@ -3944,6 +3952,14 @@ public IRubyObject storeConstant(String name, IRubyObject value) {
return constantTableStore(name, value);
}

public IRubyObject storeConstant(String name, IRubyObject value, boolean hidden) {
assert IdUtil.isConstant(name) : name + " is not a valid constant name";
assert value != null : "value is null";

ensureConstantsSettable();
return constantTableStore(name, value, hidden);
}

@Deprecated
public IRubyObject fastStoreConstant(String internedName, IRubyObject value) {
return storeConstant(internedName, value);
@@ -4042,6 +4058,12 @@ protected IRubyObject constantTableStore(String name, IRubyObject value) {
return value;
}

protected IRubyObject constantTableStore(String name, IRubyObject value, boolean hidden) {
Map<String, ConstantEntry> constMap = getConstantMapForWrite();
constMap.put(name, new ConstantEntry(value, hidden));
return value;
}

protected IRubyObject constantTableRemove(String name) {
ConstantEntry entry = getConstantMapForWrite().remove(name);
if (entry == null) return null;
8 changes: 7 additions & 1 deletion core/src/main/java/org/jruby/java/proxies/JavaProxy.java
Original file line number Diff line number Diff line change
@@ -500,6 +500,12 @@ private void confirmCachedProxy(String message) {

public static class ClassMethods {

// handling non-public inner classes retrieval ... like private constants
@JRubyMethod(name = "const_missing", required = 1, meta = true, visibility = Visibility.PRIVATE)
public static IRubyObject const_missing(ThreadContext context, IRubyObject self, IRubyObject name) {
return Java.get_inner_class(context, (RubyModule) self, name);
}

@JRubyMethod(meta = true)
public static IRubyObject java_method(ThreadContext context, IRubyObject proxyClass, IRubyObject rubyName) {
String name = rubyName.asJavaString();
@@ -558,7 +564,7 @@ public static IRubyObject java_send(ThreadContext context, IRubyObject recv, IRu
case 2: return java_send(context, recv, args[0], args[1]);
case 3: return java_send(context, recv, args[0], args[1], args[2]);
}

final Ruby runtime = context.runtime;

String name = args[0].asJavaString();
42 changes: 37 additions & 5 deletions core/src/main/java/org/jruby/javasupport/Java.java
Original file line number Diff line number Diff line change
@@ -1013,6 +1013,33 @@ public DynamicMethod dup() {

}

private static RubyModule getProxyUnderClass(final ThreadContext context,
final RubyModule enclosingClass, final String name) {
final Ruby runtime = context.runtime;

if ( name.length() == 0 ) throw runtime.newArgumentError("empty class name");

Class<?> enclosing = JavaClass.getJavaClass(context, enclosingClass);

final String fullName = enclosing.getName() + '$' + name;

final RubyModule result = getProxyClassOrNull(runtime, fullName);
//if ( result != null && cacheMethod ) bindJavaPackageOrClassMethod(enclosingClass, name, result);
return result;
}

public static IRubyObject get_inner_class(final ThreadContext context,
final RubyModule self, final IRubyObject name) { // const_missing delegate
final String constName = name.asJavaString();

final RubyModule innerClass = getProxyUnderClass(context, self, constName);
if ( innerClass == null ) { // NOTE: probably better to just call super
final String fullName = self.getName() + "::" + constName;
throw context.runtime.newNameErrorObject("uninitialized constant " + fullName, context.runtime.newSymbol(fullName));
}
return cacheConstant(self, constName, innerClass, true); // hidden == true (private_constant)
}

@JRubyMethod(meta = true)
public static IRubyObject const_missing(final ThreadContext context,
final IRubyObject self, final IRubyObject name) {
@@ -1021,18 +1048,23 @@ public static IRubyObject const_missing(final ThreadContext context,
// it's fine to not add the "cached" method here - when users sticking to
// constant access won't pay the "penalty" for adding dynamic methods ...
final RubyModule packageOrClass = getTopLevelProxyOrPackage(runtime, constName, false);
if ( packageOrClass == null ) return context.nil; // TODO compatibility (with packages)
return cacheConstant((RubyModule) self, constName, packageOrClass, false);
}

private static RubyModule cacheConstant(final RubyModule owner, // e.g. ::Java
final String constName, final RubyModule packageOrClass, final boolean hidden) {
if ( packageOrClass != null ) {
final RubyModule Java = (RubyModule) self;
// NOTE: if it's a package createPackageModule already set the constant
// ... but in case it's a (top-level) Java class name we still need to:
synchronized (Java) {
final IRubyObject alreadySet = Java.fetchConstant(constName);
synchronized (owner) {
final IRubyObject alreadySet = owner.fetchConstant(constName);
if ( alreadySet != null ) return (RubyModule) alreadySet;
Java.setConstant(constName, packageOrClass);
owner.setConstant(constName, packageOrClass, hidden);
}
return packageOrClass;
}
return context.nil; // TODO compatibility - should be throwing instead, right !?
return null;
}

@JRubyMethod(name = "method_missing", meta = true, required = 1)
2 changes: 2 additions & 0 deletions spec/java_integration/fixtures/InnerClasses.java
Original file line number Diff line number Diff line change
@@ -48,6 +48,8 @@ public interface lowerInnerInterface5 {}

protected static interface ProtectedInner {
public static String VALUE = ProtectedInner.class.getName();

class Nested extends PackageInner {}
}

static class PackageInner {
28 changes: 28 additions & 0 deletions spec/java_integration/types/retrieval_spec.rb
Original file line number Diff line number Diff line change
@@ -125,6 +125,34 @@
expect( constants ).to_not include :PrivateInner
end

it "allows to retrieve non-public inner classes" do
# InnerClasses::PackageInner
expect( InnerClasses.const_get :PackageInner ).to_not be nil
class InnerClasses
PACKAGE_INNER = PackageInner
end
expect( InnerClasses.constants ).to_not include :PackageInner
expect( InnerClasses::PACKAGE_INNER ).to eql JavaUtilities.get_proxy_class('java_integration.fixtures.InnerClasses$PackageInner')

expect( InnerClasses.const_get :PrivateInner ).to_not be nil
expect( InnerClasses.const_get :ProtectedInner ).to_not be nil

class InnerClasses
PROTECTED_INNER = ProtectedInner
end

expect( InnerClasses::PROTECTED_INNER.const_get :Nested ).to_not be nil

expect { InnerClasses::MissingInner }.to raise_error(NameError)
begin
InnerClasses.const_get :MissingInner
rescue NameError => e
expect( e.message ).to start_with 'uninitialized constant Java::Java_integrationFixtures::InnerClasses::MissingInner'
else
fail 'did not raise!'
end
end

it "raises error importing lower-case names" do
expect do
java_import InnerClasses::lowerInnerClass