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: 46683afbf097
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f3970492d679
Choose a head ref

Commits on Mar 12, 2015

  1. Fix warning.

    headius committed Mar 12, 2015
    Copy the full SHA
    94bda8d View commit details

Commits on Mar 16, 2015

  1. Copy the full SHA
    af940b1 View commit details

Commits on Mar 17, 2015

  1. Copy the full SHA
    297c953 View commit details
  2. Revert "Use JDK8 for these three...they are affected by JVM+Travis is…

    …sues."
    
    This reverts commit 297c953.
    headius committed Mar 17, 2015
    Copy the full SHA
    df6bae2 View commit details
  3. Copy the full SHA
    14d1d29 View commit details

Commits on Mar 18, 2015

  1. correct (Java) equals/hashCode semantics for JavaAccessibleObject + m…

    …inor tweaks
    
    - return concrete types from getValue
    - also re-implemented (inherited) toJava conversion
    kares committed Mar 18, 2015
    Copy the full SHA
    d7217ca View commit details
  2. Copy the full SHA
    1337fbe View commit details
  3. Copy the full SHA
    015d9b4 View commit details
  4. Copy the full SHA
    1c5c4a3 View commit details
  5. Copy the full SHA
    ee0113e View commit details
  6. Copy the full SHA
    03acf55 View commit details
  7. Copy the full SHA
    ebc2422 View commit details
  8. Copy the full SHA
    0de8bdf View commit details
  9. Copy the full SHA
    b997129 View commit details
  10. add a factory onto ClassValue since we're be instantiating the same (…

    …based on opt)
    
    - JavaSupport internals now no longer deal with ClassValue impl constructors
    kares committed Mar 18, 2015
    Copy the full SHA
    cfa0011 View commit details
  11. Copy the full SHA
    99a4c30 View commit details
  12. Copy the full SHA
    bf85781 View commit details
  13. Copy the full SHA
    07e87cc View commit details
  14. Copy the full SHA
    9902ebd View commit details
  15. Copy the full SHA
    411086d View commit details
  16. re-factored candidate matching loops - for more readability and less …

    …implicit iterator use
    kares committed Mar 18, 2015
    Copy the full SHA
    b5c5e2b View commit details
  17. Copy the full SHA
    3635300 View commit details
  18. in case there's an exact parameter match - do not proceed with argume…

    …nt matching
    
    ... towards fixing #2595
    kares committed Mar 18, 2015
    Copy the full SHA
    6521ee4 View commit details
  19. 4
    Copy the full SHA
    adeb887 View commit details

Commits on Mar 19, 2015

  1. Merge branch 'jruby-1_7' into master

    * jruby-1_7: (24 commits)
      calculate 'sofisticated' type preference when ambiguous callables found (fixes #2595)
      in case there's an exact parameter match - do not proceed with argument matching
      do not do equals on Class objects (just compare by identity) + remove unused imports
      re-factored candidate matching loops - for more readability and less implicit iterator use
      cleanup the constructor search - keeping redundant ~ 'intended' code as comments
      a slight Java integration (mostly bootstrap internals) cleanup
      update CallableSelector's (Map) cache internals - so we can easily refactor further
      move Java.method_missing into native
      loadPaths list generics - easier to guess for JavaEmbedUtils consumers
      add a factory onto ClassValue since we're be instantiating the same (based on opt)
      one JRubyMethod with 2 names is enough to have
      more base-class sharing between JavaCallable method/constructor impl + minor tweaks
      move getArity/getParameterTypes into base class as finals + help used methods to JIT
      guess name-class hash-map size without internal resizing (currently <= 48 elements)
      after several concurrency fixes in Java integration - un-comment a multi-threaded test
      non need to cast intValue to (int)
      move (and tune) error logic from CallableSelector into the invoker impl where it's used
      align JavaField's value/static_value conversions and return values + test functionality
      correct (Java) equals/hashCode semantics for JavaAccessibleObject + minor tweaks
      Try turning off sudo:false to fix build issues.
      ...
    
    Conflicts:
    	.travis.yml
    	core/src/main/java/org/jruby/RubyObject.java
    	core/src/main/java/org/jruby/java/proxies/MapJavaProxy.java
    	core/src/main/java/org/jruby/javasupport/JavaCallable.java
    	core/src/main/java/org/jruby/javasupport/JavaEmbedUtils.java
    	core/src/main/java/org/jruby/javasupport/JavaSupport.java
    	core/src/main/java/org/jruby/runtime/Helpers.java
    	core/src/main/java/org/jruby/util/CodegenUtils.java
    	core/src/main/ruby/jruby/java.rb
    	core/src/test/java/org/jruby/test/TestCodeCache.java
    	test/test_higher_javasupport.rb
    kares committed Mar 19, 2015
    Copy the full SHA
    f2b9bf7 View commit details
  2. Merge branch 'master' of github.com:jruby/jruby

    * 'master' of github.com:jruby/jruby: (56 commits)
      [Truffle] Renamed some classes to generate smaller filenames.
      [Truffle] Moving Array#join to array.rb.
      [Truffle] FindBugs: remove unused fields.
      [Truffle] JT: Remove useless enumerator.
      [Truffle] JT: Move paths inside the methods using them.
      [Truffle] JT: Find appropriate Graal based on Truffle version.
      [Truffle] JT: Do not specify full path.
      Re-tag exposed failures in m17n_comb while we fix on a branch.
      [Truffle] JT: Rename Utilities.branch to git_branch.
      [Truffle] Refactoring ReturnEnumeratorIfNoBlockNode arguments unshift into RubyArguments method.
      [Truffle] Fix hardcoded path and grammar.
      [Truffle] Allow GRAAL_BIN to be set per branch by an environment variable.
      [Truffle] jt run --igv option.
      [Truffle] No such thing as a FrozenError.
      implements strict base64 encoding
      [build] regenerate pom.xml [skip ci]
      [Truffle] Fix SourceSection identifier for def* nodes.
      [build] remove warning on duplicate plugin definitions [skip ci]
      [Truffle] Implementing more of Array#concat
      [Truffle] Display non-aliased (called) name in backtrace of core methods.
      ...
    kares committed Mar 19, 2015
    Copy the full SHA
    96ee1d8 View commit details
  3. Copy the full SHA
    5eccb58 View commit details
  4. Copy the full SHA
    a9f34c8 View commit details
  5. Copy the full SHA
    58ab443 View commit details
  6. Copy the full SHA
    f397049 View commit details
Showing with 1,274 additions and 1,104 deletions.
  1. +19 −21 core/src/main/java/org/jruby/RubyObject.java
  2. +261 −249 core/src/main/java/org/jruby/java/dispatch/CallableSelector.java
  3. +66 −9 core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java
  4. +3 −3 core/src/main/java/org/jruby/java/proxies/ConcreteJavaProxy.java
  5. +24 −24 core/src/main/java/org/jruby/java/proxies/MapJavaProxy.java
  6. +55 −39 core/src/main/java/org/jruby/javasupport/Java.java
  7. +40 −18 core/src/main/java/org/jruby/javasupport/JavaAccessibleObject.java
  8. +15 −12 core/src/main/java/org/jruby/javasupport/JavaArray.java
  9. +92 −44 core/src/main/java/org/jruby/javasupport/JavaCallable.java
  10. +82 −71 core/src/main/java/org/jruby/javasupport/JavaClass.java
  11. +81 −117 core/src/main/java/org/jruby/javasupport/JavaConstructor.java
  12. +10 −10 core/src/main/java/org/jruby/javasupport/JavaEmbedUtils.java
  13. +55 −70 core/src/main/java/org/jruby/javasupport/JavaField.java
  14. +33 −63 core/src/main/java/org/jruby/javasupport/JavaMethod.java
  15. +9 −9 core/src/main/java/org/jruby/javasupport/JavaObject.java
  16. +0 −1 core/src/main/java/org/jruby/javasupport/JavaSupport.java
  17. +33 −69 core/src/main/java/org/jruby/javasupport/JavaSupportImpl.java
  18. +209 −205 core/src/main/java/org/jruby/runtime/Helpers.java
  19. +22 −23 core/src/main/java/org/jruby/util/CodegenUtils.java
  20. +32 −3 core/src/main/java/org/jruby/util/collections/ClassValue.java
  21. +1 −2 core/src/main/ruby/jruby/java.rb
  22. +1 −8 core/src/main/ruby/jruby/java/java_module.rb
  23. +3 −3 core/src/test/java/org/jruby/runtime/EventHookTest.java
  24. +95 −26 test/jruby/test_higher_javasupport.rb
  25. +22 −0 truffle/src/main/java/org/jruby/truffle/nodes/core/StringGuards.java
  26. +8 −1 truffle/src/main/java/org/jruby/truffle/nodes/core/StringNodes.java
  27. +3 −4 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/StringPrimitiveNodes.java
40 changes: 19 additions & 21 deletions core/src/main/java/org/jruby/RubyObject.java
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@
* RubyObject represents the implementation of the Object class in Ruby. As such,
* it defines very few methods of its own, inheriting most from the included
* Kernel module.
*
*
* Methods that are implemented here, such as "initialize" should be implemented
* with care; reification of Ruby classes into Java classes can produce
* conflicting method names in rare cases. See JRUBY-5906 for an example.
@@ -139,77 +139,77 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObject(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR0_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar0(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR1_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar1(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR2_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar2(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR3_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar3(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR4_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar4(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR5_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar5(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR6_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar6(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR7_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar7(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR8_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar8(runtime, klass);
}
};

public static final ObjectAllocator OBJECT_VAR9_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyObjectVar9(runtime, klass);
}
};

public static final ObjectAllocator[] FIELD_ALLOCATORS = {
OBJECT_ALLOCATOR,
OBJECT_VAR0_ALLOCATOR,
@@ -223,7 +223,7 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
OBJECT_VAR8_ALLOCATOR,
OBJECT_VAR9_ALLOCATOR
};

public static final Class[] FIELD_ALLOCATED_CLASSES = {
RubyObject.class,
RubyObjectVar0.class,
@@ -237,7 +237,7 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
RubyObjectVar8.class,
RubyObjectVar9.class,
};

/**
* Allocator that inspects all methods for instance variables and chooses
* a concrete class to construct based on that. This allows using
@@ -252,19 +252,19 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
if (Options.DUMP_INSTANCE_VARS.load()) {
System.err.println(klass + ";" + foundVariables);
}

int count = 0;
for (String name : foundVariables) {
klass.getVariableTableManager().getVariableAccessorForVar(name, count);
count++;
if (count >= 10) break;
}

ObjectAllocator allocator = FIELD_ALLOCATORS[count];
Class reified = FIELD_ALLOCATED_CLASSES[count];
klass.setAllocator(allocator);
klass.setReifiedClass(reified);

return allocator.allocate(runtime, klass);
}
};
@@ -516,13 +516,11 @@ public int hashCode() {
}

private int nonFixnumHashCode(IRubyObject hashValue) {
Ruby runtime = getRuntime();
RubyInteger integer = hashValue.convertToInteger();
if (integer instanceof RubyBignum) {
return (int)integer.getBigIntegerValue().intValue();
} else {
return (int)integer.getLongValue();
return integer.getBigIntegerValue().intValue();
}
return (int) integer.getLongValue();
}

/** rb_inspect
510 changes: 261 additions & 249 deletions core/src/main/java/org/jruby/java/dispatch/CallableSelector.java

Large diffs are not rendered by default.

75 changes: 66 additions & 9 deletions core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java
Original file line number Diff line number Diff line change
@@ -12,15 +12,20 @@
import java.util.concurrent.ConcurrentHashMap;
import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.methods.CallConfiguration;
import org.jruby.internal.runtime.methods.JavaMethod;
import org.jruby.java.dispatch.CallableSelector;
import org.jruby.java.proxies.ArrayJavaProxy;
import org.jruby.java.proxies.ConcreteJavaProxy;
import org.jruby.java.proxies.JavaProxy;
import org.jruby.javasupport.JavaCallable;
import org.jruby.javasupport.JavaConstructor;
import org.jruby.javasupport.ParameterTypes;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.CodegenUtils;
import org.jruby.util.collections.IntHashMap;

public abstract class RubyToJavaInvoker extends JavaMethod {
@@ -105,13 +110,13 @@ public abstract class RubyToJavaInvoker extends JavaMethod {
if (javaCallable != null) {
// no constructor support yet
if (javaCallable instanceof org.jruby.javasupport.JavaMethod) {
setNativeCallIfPublic( (Method) ((org.jruby.javasupport.JavaMethod) javaCallable).getValue() );
setNativeCallIfPublic( ((org.jruby.javasupport.JavaMethod) javaCallable).getValue() );
}
} else { // use the lowest-arity non-overload
for (JavaCallable[] callablesForArity : javaCallables) {
if ( callablesForArity == null || callablesForArity.length != 1 ) continue;
if ( callablesForArity[0] instanceof org.jruby.javasupport.JavaMethod ) {
setNativeCallIfPublic( (Method) ((org.jruby.javasupport.JavaMethod) callablesForArity[0]).getValue() );
setNativeCallIfPublic( ((org.jruby.javasupport.JavaMethod) callablesForArity[0]).getValue() );
}
}
}
@@ -201,7 +206,7 @@ protected JavaCallable findCallable(IRubyObject self, String name, IRubyObject[]
if (javaVarargsCallables != null) {
callable = CallableSelector.matchingCallableArityN(runtime, cache, javaVarargsCallables, args, arity);
if (callable == null) {
throw CallableSelector.argTypesDoNotMatch(runtime, self, javaVarargsCallables, (Object[])args);
throw newNameErrorDueArgumentTypeMismatch(runtime, self, javaVarargsCallables, args);
}
return callable;
} else {
@@ -212,12 +217,12 @@ protected JavaCallable findCallable(IRubyObject self, String name, IRubyObject[]
if (callable == null && javaVarargsCallables != null) {
callable = CallableSelector.matchingCallableArityN(runtime, cache, javaVarargsCallables, args, arity);
if (callable == null) {
throw CallableSelector.argTypesDoNotMatch(runtime, self, javaVarargsCallables, (Object[])args);
throw newNameErrorDueArgumentTypeMismatch(runtime, self, javaVarargsCallables, args);
}
return callable;
}
if (callable == null) {
throw CallableSelector.argTypesDoNotMatch(runtime, self, callablesForArity, (Object[])args);
throw newNameErrorDueArgumentTypeMismatch(runtime, self, callablesForArity, args);
}
} else {
if (!callable.isVarArgs() && callable.getParameterTypes().length != args.length) {
@@ -254,7 +259,7 @@ protected JavaCallable findCallableArityOne(IRubyObject self, String name, IRuby
}
callable = CallableSelector.matchingCallableArityOne(runtime, cache, callablesForArity, arg0);
if (callable == null) {
throw CallableSelector.argTypesDoNotMatch(runtime, self, callablesForArity, arg0);
throw newNameErrorDueArgumentTypeMismatch(runtime, self, callablesForArity, arg0);
}
} else {
if (callable.getParameterTypes().length != 1) {
@@ -274,7 +279,7 @@ protected JavaCallable findCallableArityTwo(IRubyObject self, String name, IRuby
}
callable = CallableSelector.matchingCallableArityTwo(runtime, cache, callablesForArity, arg0, arg1);
if (callable == null) {
throw CallableSelector.argTypesDoNotMatch(runtime, self, callablesForArity, arg0, arg1);
throw newNameErrorDueArgumentTypeMismatch(runtime, self, callablesForArity, arg0, arg1);
}
} else {
if (callable.getParameterTypes().length != 2) {
@@ -294,7 +299,7 @@ protected JavaCallable findCallableArityThree(IRubyObject self, String name, IRu
}
callable = CallableSelector.matchingCallableArityThree(runtime, cache, callablesForArity, arg0, arg1, arg2);
if (callable == null) {
throw CallableSelector.argTypesDoNotMatch(runtime, self, callablesForArity, arg0, arg1, arg2);
throw newNameErrorDueArgumentTypeMismatch(runtime, self, callablesForArity, arg0, arg1, arg2);
}
} else {
if (callable.getParameterTypes().length != 3) {
@@ -314,7 +319,7 @@ protected JavaCallable findCallableArityFour(IRubyObject self, String name, IRub
}
callable = CallableSelector.matchingCallableArityFour(runtime, cache, callablesForArity, arg0, arg1, arg2, arg3);
if (callable == null) {
throw CallableSelector.argTypesDoNotMatch(runtime, self, callablesForArity, arg0, arg1, arg2, arg3);
throw newNameErrorDueArgumentTypeMismatch(runtime, self, callablesForArity, arg0, arg1, arg2, arg3);
}
} else {
if (callable.getParameterTypes().length != 4) {
@@ -323,4 +328,56 @@ protected JavaCallable findCallableArityFour(IRubyObject self, String name, IRub
}
return callable;
}

static RaiseException newNameErrorDueArgumentTypeMismatch(final Ruby runtime,
final IRubyObject receiver, final JavaCallable[] methods, IRubyObject... args) {

final Class[] argTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
argTypes[i] = getClass( args[i] );
}

final boolean constructor = methods[0] instanceof JavaConstructor; // || methods[0] instanceof JavaProxyConstructor;

final StringBuilder error = new StringBuilder(32);

error.append("no ");
if ( constructor ) {
error.append("constructor");
}
else {
org.jruby.javasupport.JavaMethod method = (org.jruby.javasupport.JavaMethod) methods[0];
error.append("method '").append( method.getValue().getName() ).append("'");
}
error.append(" for arguments ")
.append( CodegenUtils.prettyParams(argTypes) )
.append(" on ");

if (receiver instanceof RubyModule) {
error.append( ((RubyModule) receiver).getName() );
} else {
error.append( receiver.getMetaClass().getRealClass().getName() );
}

if (methods.length > 1) {
error.append("\n available overloads:");
for (ParameterTypes method : methods) {
Class<?>[] paramTypes = method.getParameterTypes();
error.append("\n ").append( CodegenUtils.prettyParams(paramTypes) );
}
}

// TODO should have been ArgumentError - might break users to refactor at this point
return runtime.newNameError(error.toString(), null);
}

private static Class<?> getClass(final IRubyObject object) {
if (object == null) return void.class;

if (object instanceof ConcreteJavaProxy) {
return ((ConcreteJavaProxy)object).getJavaClass();
}
return object.getClass();
}

}
Original file line number Diff line number Diff line change
@@ -173,12 +173,12 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz

}

protected static void initialize(final RubyClass concreteJavaProxy) {
concreteJavaProxy.addMethod("initialize", new InitializeMethod(concreteJavaProxy));
protected static void initialize(final RubyClass ConcreteJavaProxy) {
ConcreteJavaProxy.addMethod("initialize", new InitializeMethod(ConcreteJavaProxy));
// We define a custom "new" method to ensure that __jcreate! is getting called,
// so that if the user doesn't call super in their subclasses, the object will
// still get set up properly. See JRUBY-4704.
RubyClass singleton = concreteJavaProxy.getSingletonClass();
RubyClass singleton = ConcreteJavaProxy.getSingletonClass();
singleton.addMethod("new", new NewMethod(singleton));
}

48 changes: 24 additions & 24 deletions core/src/main/java/org/jruby/java/proxies/MapJavaProxy.java
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
* rights and limitations under the License.
*
* Copyright (C) 2011 Yoko Harada <yokolet@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,7 +48,7 @@
import java.util.Set;

/**
*
*
* @author Yoko Harada
*/

@@ -63,21 +63,21 @@ public MapJavaProxy(Ruby runtime, RubyClass klazz, Map map) {
super(runtime, klazz, map);
}

public static RubyClass createMapJavaProxy(ThreadContext context) {
Ruby runtime = context.runtime;
private static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
public MapJavaProxy allocate(Ruby runtime, RubyClass klazz) {
return new MapJavaProxy(runtime, klazz);
}
};

RubyClass mapJavaProxy = runtime.defineClass("MapJavaProxy",
runtime.getJavaSupport().getConcreteProxyClass(),
new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
return new MapJavaProxy(runtime, klazz);
}
});
public static RubyClass createMapJavaProxy(final Ruby runtime) {
RubyClass MapJavaProxy = runtime.defineClass(
"MapJavaProxy", runtime.getJavaSupport().getConcreteProxyClass(), ALLOCATOR
);
// this is done while proxy class is created.
// See org.jruby.javasuppoer.java.createProxyClass()
//mapJavaProxy.defineAnnotatedMethods(MapJavaProxy.class);
ConcreteJavaProxy.initialize(mapJavaProxy);
return mapJavaProxy;
// MapJavaProxy.defineAnnotatedMethods(MapJavaProxy.class);
ConcreteJavaProxy.initialize(MapJavaProxy);
return MapJavaProxy;
}

private RubyHashMap getOrCreateRubyHashMap() {
@@ -103,11 +103,11 @@ public RubyHashMap(Ruby runtime, IRubyObject receiver) {
super(runtime);
this.receiver = receiver;
}

private void setSize(int size) {
this.size = size;
}

private Map getMap() {
return (Map) ((JavaProxy)receiver).getObject();
}
@@ -131,12 +131,12 @@ public RubyHashEntry internalGetEntry(IRubyObject key) {
Map map = getMap();
Object convertedKey = key.toJava(Object.class);
Object value = map.get(convertedKey);

if (value != null) {
RubyHashEntry rubyEntry = new RubyHashEntry(key.hashCode(), key, JavaUtil.convertJavaToUsableRubyObject(getRuntime(), value), null, null);
return rubyEntry;
}

return NO_ENTRY;
}

@@ -145,28 +145,28 @@ public RubyHashEntry internalDelete(final IRubyObject key) {
Map map = getMap();
Object convertedKey = key.toJava(Object.class);
Object value = map.get(convertedKey);

if (value != null) {
RubyHashEntry rubyEntry = new RubyHashEntry(key.hashCode(), key, JavaUtil.convertJavaToUsableRubyObject(getRuntime(), value), null, null);
map.remove(convertedKey);
size = map.size();
return rubyEntry;
}

return NO_ENTRY;
}

@Override
public RubyHashEntry internalDeleteEntry(final RubyHashEntry entry) {
Map map = getMap();
Object convertedKey = ((IRubyObject)entry.getKey()).toJava(Object.class);

if (map.containsKey(convertedKey)) {
map.remove(convertedKey);
size = map.size();
return entry;
}

return NO_ENTRY;
}

@@ -195,7 +195,7 @@ public RubyHash rehash() {
public RubyHash rb_clear() {
getMap().clear();
size = 0;

return this;
}

@@ -357,7 +357,7 @@ public RubyFixnum hash() {
public IRubyObject fetch(ThreadContext context, IRubyObject key, Block block) {
return getOrCreateRubyHashMap().fetch(context, key, block);
}

@JRubyMethod
public IRubyObject fetch(ThreadContext context, IRubyObject key, IRubyObject _default, Block block) {
return getOrCreateRubyHashMap().fetch(context, key, _default, block);
94 changes: 55 additions & 39 deletions core/src/main/java/org/jruby/javasupport/Java.java
Original file line number Diff line number Diff line change
@@ -124,9 +124,9 @@ public void load(Ruby runtime, boolean wrap) {
runtime.getLoadService().load("jruby/java.rb", false);

// rewite ArrayJavaProxy superclass to point at Object, so it inherits Object behaviors
RubyClass ajp = runtime.getClass("ArrayJavaProxy");
ajp.setSuperClass(runtime.getJavaSupport().getObjectJavaClass().getProxyClass());
ajp.includeModule(runtime.getEnumerable());
final RubyClass ArrayJavaProxy = runtime.getClass("ArrayJavaProxy");
ArrayJavaProxy.setSuperClass(runtime.getJavaSupport().getObjectJavaClass().getProxyClass());
ArrayJavaProxy.includeModule(runtime.getEnumerable());

RubyClassPathVariable.createClassPathVariable(runtime);

@@ -138,18 +138,20 @@ public void load(Ruby runtime, boolean wrap) {
runtime.getObject().setConstantQuiet("ENV_JAVA", new MapJavaProxy(runtime, proxyClass, systemProperties));
}

@SuppressWarnings("deprecation")
public static RubyModule createJavaModule(final Ruby runtime) {
ThreadContext context = runtime.getCurrentContext();
RubyModule javaModule = runtime.defineModule("Java");
final ThreadContext context = runtime.getCurrentContext();

final RubyModule Java = runtime.defineModule("Java");

javaModule.defineAnnotatedMethods(Java.class);
Java.defineAnnotatedMethods(Java.class);

JavaObject.createJavaObjectClass(runtime, javaModule);
JavaArray.createJavaArrayClass(runtime, javaModule);
JavaClass.createJavaClassClass(runtime, javaModule);
JavaMethod.createJavaMethodClass(runtime, javaModule);
JavaConstructor.createJavaConstructorClass(runtime, javaModule);
JavaField.createJavaFieldClass(runtime, javaModule);
final RubyClass _JavaObject = JavaObject.createJavaObjectClass(runtime, Java);
JavaArray.createJavaArrayClass(runtime, Java, _JavaObject);
JavaClass.createJavaClassClass(runtime, Java, _JavaObject);
JavaMethod.createJavaMethodClass(runtime, Java);
JavaConstructor.createJavaConstructorClass(runtime, Java);
JavaField.createJavaFieldClass(runtime, Java);

// set of utility methods for Java-based proxy objects
JavaProxyMethods.createJavaProxyMethods(context);
@@ -162,17 +164,15 @@ public static RubyModule createJavaModule(final Ruby runtime) {
ArrayJavaProxy.createArrayJavaProxy(context);

// creates ruby's hash methods' proxy for Map interface
MapJavaProxy.createMapJavaProxy(context);
MapJavaProxy.createMapJavaProxy(runtime);

// also create the JavaProxy* classes
JavaProxyClass.createJavaProxyModule(runtime);

// The template for interface modules
JavaInterfaceTemplate.createJavaInterfaceTemplateModule(context);

RubyModule javaUtils = runtime.defineModule("JavaUtilities");

javaUtils.defineAnnotatedMethods(JavaUtilities.class);
runtime.defineModule("JavaUtilities").defineAnnotatedMethods(JavaUtilities.class);

JavaArrayUtilities.createJavaArrayUtilitiesModule(runtime);

@@ -192,7 +192,7 @@ public static RubyModule createJavaModule(final Ruby runtime) {
// add some base Java classes everyone will need
runtime.getJavaSupport().setObjectJavaClass( JavaClass.get(runtime, Object.class) );

return javaModule;
return Java;
}

public static class OldStyleExtensionInherited {
@@ -722,10 +722,11 @@ public static IRubyObject concrete_proxy_inherited(final IRubyObject clazz, fina
if ( ! ( subclazz instanceof RubyClass ) ) {
throw runtime.newTypeError(subclazz, runtime.getClassClass());
}
return setupJavaSubclass(context, (RubyClass) subclazz);
setupJavaSubclass(context, (RubyClass) subclazz);
return context.nil;
}

private static IRubyObject setupJavaSubclass(final ThreadContext context, final RubyClass subclass) {
private static void setupJavaSubclass(final ThreadContext context, final RubyClass subclass) {

subclass.getInstanceVariables().setInstanceVariable("@java_proxy_class", context.nil);

@@ -753,17 +754,15 @@ public IRubyObject call(final ThreadContext context, IRubyObject self, RubyModul
self.getMetaClass().getInstanceVariables().setInstanceVariable("@java_proxy_class", proxyClass);
}

JavaProxyClass realProxyClass = (JavaProxyClass)proxyClass;
RubyArray constructors = realProxyClass.constructors();
ArrayList<JavaProxyConstructor> forArity = new ArrayList<JavaProxyConstructor>();
for (int i = 0; i < constructors.size(); i++) {
JavaProxyConstructor constructor = (JavaProxyConstructor)constructors.eltInternal(i);
if (constructor.getParameterTypes().length == args.length) {
forArity.add(constructor);
}
final int argsLength = args.length;
final RubyArray constructors = ((JavaProxyClass) proxyClass).constructors();
ArrayList<JavaProxyConstructor> forArity = new ArrayList<JavaProxyConstructor>(constructors.size());
for ( int i = 0; i < constructors.size(); i++ ) {
JavaProxyConstructor constructor = (JavaProxyConstructor) constructors.eltInternal(i);
if ( constructor.getParameterTypes().length == argsLength ) forArity.add(constructor);
}

if (forArity.size() == 0) {
if ( forArity.size() == 0 ) {
throw context.runtime.newArgumentError("wrong number of arguments for constructor");
}

@@ -775,18 +774,16 @@ public IRubyObject call(final ThreadContext context, IRubyObject self, RubyModul
throw context.runtime.newArgumentError("wrong number of arguments for constructor");
}

Object[] newArgs = new Object[args.length];
final Object[] javaArgs = new Object[argsLength];
Class[] parameterTypes = matching.getParameterTypes();
for (int i = 0; i < args.length; i++) {
newArgs[i] = args[i].toJava(parameterTypes[i]);
for ( int i = 0; i < argsLength; i++ ) {
javaArgs[i] = args[i].toJava(parameterTypes[i]);
}

JavaObject newObject = matching.newInstance(self, newArgs);
JavaObject newObject = matching.newInstance(self, javaArgs);
return JavaUtilities.set_java_object(self, self, newObject);
}
});

return context.nil;
}

// package scheme 2: separate module for each full package name, constructed
@@ -1112,19 +1109,39 @@ public static IRubyObject const_missing(final ThreadContext context,
// constant access won't pay the "penalty" for adding dynamic methods ...
final RubyModule packageOrClass = getTopLevelProxyOrPackage(runtime, constName, false);
if ( packageOrClass != null ) {
final RubyModule javaModule = (RubyModule) self;
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 (javaModule) {
final IRubyObject alreadySet = javaModule.fetchConstant(constName);
synchronized (Java) {
final IRubyObject alreadySet = Java.fetchConstant(constName);
if ( alreadySet != null ) return (RubyModule) alreadySet;
javaModule.setConstant(constName, packageOrClass);
Java.setConstant(constName, packageOrClass);
}
return packageOrClass;
}
return context.nil; // TODO compatibility - should be throwing instead, right !?
}

@JRubyMethod(name = "method_missing", meta = true, required = 1)
public static IRubyObject method_missing(ThreadContext context, final IRubyObject self,
final IRubyObject name) { // JavaUtilities.get_top_level_proxy_or_package(name)
// NOTE: getTopLevelProxyOrPackage will bind the (cached) method for us :
final RubyModule result = getTopLevelProxyOrPackage(context.runtime, name.asJavaString(), true);
if ( result != null ) return result;
return context.nil; // TODO compatibility - should be throwing instead, right !?
}

@JRubyMethod(name = "method_missing", meta = true, rest = true)
public static IRubyObject method_missing(ThreadContext context, final IRubyObject self,
final IRubyObject[] args) {
final IRubyObject name = args[0];
if ( args.length > 1 ) {
final int count = args.length - 1;
throw context.runtime.newArgumentError("Java does not have a method `"+ name +"' with " + count + " arguments");
}
return method_missing(context, self, name);
}

public static IRubyObject get_top_level_proxy_or_package(final ThreadContext context,
final IRubyObject self, final IRubyObject name) {
final RubyModule result = getTopLevelProxyOrPackage(context.runtime, name.asJavaString(), true);
@@ -1150,7 +1167,6 @@ public static IRubyObject java_to_ruby(IRubyObject recv, IRubyObject object, Blo
}
}

// TODO: Formalize conversion mechanisms between Java and Ruby
/**
* High-level object conversion utility.
*/
58 changes: 40 additions & 18 deletions core/src/main/java/org/jruby/javasupport/JavaAccessibleObject.java
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
*
* Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
* Copyright (C) 2004 David Corbin <dcorbin@users.sourceforge.net>
*
*
* 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"),
@@ -52,13 +52,19 @@ public static void registerRubyMethods(Ruby runtime, RubyClass result) {

public abstract AccessibleObject accessibleObject();

public boolean equals(Object other) {
public boolean equals(final Object other) {
if ( this == other ) return true;
return other instanceof JavaAccessibleObject &&
this.accessibleObject() == ((JavaAccessibleObject) other).accessibleObject();
this.accessibleObject().equals( ((JavaAccessibleObject) other).accessibleObject() );
}

boolean same(final JavaAccessibleObject that) {
if ( this == that ) return true;
return this.accessibleObject() == that.accessibleObject();
}

public int hashCode() {
return this.accessibleObject().hashCode();
return accessibleObject().hashCode();
}

@JRubyMethod
@@ -67,13 +73,14 @@ public RubyFixnum hash() {
}

@JRubyMethod(name = {"==", "eql?"})
public IRubyObject op_equal(IRubyObject other) {
return other instanceof JavaAccessibleObject && accessibleObject().equals(((JavaAccessibleObject) other).accessibleObject()) ? getRuntime().getTrue() : getRuntime().getFalse();
public RubyBoolean op_equal(final IRubyObject other) {
return RubyBoolean.newBoolean(getRuntime(), equals(other));
}

@JRubyMethod(name = "equal?")
public IRubyObject same(IRubyObject other) {
return getRuntime().newBoolean(equals(other));
public RubyBoolean same(final IRubyObject other) {
final boolean same = other instanceof JavaAccessibleObject && same((JavaAccessibleObject) other);
return same ? getRuntime().getTrue() : getRuntime().getFalse();
}

@JRubyMethod(name = "accessible?")
@@ -89,11 +96,12 @@ public IRubyObject setAccessible(IRubyObject object) {

@SuppressWarnings("unchecked")
@JRubyMethod
public IRubyObject annotation(IRubyObject annoClass) {
if (!(annoClass instanceof JavaClass)) {
public IRubyObject annotation(final IRubyObject annoClass) {
if ( ! ( annoClass instanceof JavaClass ) ) {
throw getRuntime().newTypeError(annoClass, getRuntime().getJavaSupport().getJavaClassClass());
}
return Java.getInstance(getRuntime(), accessibleObject().getAnnotation(((JavaClass) annoClass).javaClass()));
final Class annotation = ((JavaClass) annoClass).javaClass();
return Java.getInstance(getRuntime(), accessibleObject().getAnnotation(annotation));
}

@JRubyMethod
@@ -116,22 +124,22 @@ public RubyBoolean declared_annotations_p() {
return getRuntime().newBoolean(accessibleObject().getDeclaredAnnotations().length > 0);
}

@SuppressWarnings("unchecked")
@JRubyMethod(name = "annotation_present?")
public IRubyObject annotation_present_p(IRubyObject annoClass) {
if (!(annoClass instanceof JavaClass)) {
public IRubyObject annotation_present_p(final IRubyObject annoClass) {
if ( ! ( annoClass instanceof JavaClass ) ) {
throw getRuntime().newTypeError(annoClass, getRuntime().getJavaSupport().getJavaClassClass());
}
return getRuntime().newBoolean(this.accessibleObject().isAnnotationPresent(((JavaClass) annoClass).javaClass()));
final Class annotation = ((JavaClass) annoClass).javaClass();
return getRuntime().newBoolean( accessibleObject().isAnnotationPresent(annotation) );
}

// for our purposes, Accessibles are also Members, and vice-versa,
// so we'll include Member methods here.
@JRubyMethod
public IRubyObject declaring_class() {
Class<?> clazz = ((Member) accessibleObject()).getDeclaringClass();
if (clazz != null) {
return JavaClass.get(getRuntime(), clazz);
}
if ( clazz != null ) return JavaClass.get(getRuntime(), clazz);
return getRuntime().getNil();
}

@@ -152,6 +160,20 @@ public IRubyObject synthetic_p() {

@JRubyMethod(name = {"to_s", "to_string"})
public RubyString to_string() {
return getRuntime().newString(accessibleObject().toString());
return getRuntime().newString( toString() );
}

@Override
public String toString() {
return accessibleObject().toString();
}

@Override
public Object toJava(Class target) {
if ( AccessibleObject.class.isAssignableFrom(target) ) {
return accessibleObject();
}
return super.toJava(target);
}

}
27 changes: 15 additions & 12 deletions core/src/main/java/org/jruby/javasupport/JavaArray.java
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
* Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
* Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
* Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
*
*
* 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"),
@@ -44,20 +44,23 @@

@JRubyClass(name="Java::JavaArray", parent="Java::JavaObject")
public class JavaArray extends JavaObject {
private JavaUtil.JavaConverter javaConverter;


private final JavaUtil.JavaConverter javaConverter;

public JavaArray(Ruby runtime, Object array) {
super(runtime, runtime.getJavaSupport().getJavaArrayClass(), array);
assert array.getClass().isArray();
javaConverter = JavaUtil.getJavaConverter(array.getClass().getComponentType());
}

public static RubyClass createJavaArrayClass(Ruby runtime, RubyModule javaModule) {
// FIXME: NOT_ALLOCATABLE_ALLOCATOR is probably not right here, since we might
// eventually want JavaArray to be marshallable. JRUBY-414
return javaModule.defineClassUnder("JavaArray", javaModule.getClass("JavaObject"), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
public static RubyClass createJavaArrayClass(final Ruby runtime, final RubyModule Java) {
return createJavaArrayClass(runtime, Java, Java.getClass("JavaObject"));
}

static RubyClass createJavaArrayClass(final Ruby runtime, RubyModule Java, RubyClass JavaObject) {
return Java.defineClassUnder("JavaArray", JavaObject, ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
}

public Class getComponentType() {
return getValue().getClass().getComponentType();
}
@@ -88,16 +91,16 @@ public IRubyObject aset(IRubyObject index, IRubyObject value) {
throw getRuntime().newTypeError("not a java object:" + value);
}
Object javaObject = ((JavaObject) value).getValue();

ArrayUtils.setWithExceptionHandlingDirect(getRuntime(), javaObject, intIndex, javaObject);

return value;
}

public IRubyObject asetDirect(Ruby runtime, int intIndex, IRubyObject value) {
return ArrayUtils.asetDirect(runtime, getValue(), javaConverter, intIndex, value);
}

public void setWithExceptionHandling(int intIndex, Object javaObject) {
ArrayUtils.setWithExceptionHandlingDirect(getRuntime(), getValue(), intIndex, javaObject);
}
@@ -118,7 +121,7 @@ public IRubyObject afill(IRubyObject beginIndex, IRubyObject endIndex, IRubyObje
fillWithExceptionHandling(intIndex, intEndIndex, javaObject);
return value;
}

public void fillWithExceptionHandling(int intIndex, int intEndIndex, Object javaObject) {
try {
for ( ; intIndex < intEndIndex; intIndex++) {
136 changes: 92 additions & 44 deletions core/src/main/java/org/jruby/javasupport/JavaCallable.java
Original file line number Diff line number Diff line change
@@ -31,8 +31,10 @@
package org.jruby.javasupport;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;

@@ -43,13 +45,15 @@
import org.jruby.RubyFixnum;
import org.jruby.RubyString;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.cli.Options;
import static org.jruby.javasupport.JavaClass.toRubyArray;

public abstract class JavaCallable extends JavaAccessibleObject implements ParameterTypes {

protected final Class<?>[] parameterTypes;

private static final boolean REWRITE_JAVA_TRACE = Options.REWRITE_JAVA_TRACE.load();
@@ -63,15 +67,20 @@ public static void registerRubyMethods(Ruby runtime, RubyClass result) {
result.defineAnnotatedMethods(JavaCallable.class);
}

public abstract int getArity();
public final int getArity() { return parameterTypes.length; }

public final Class<?>[] getParameterTypes() { return parameterTypes; }

//public abstract int getArity();
//public abstract Class<?>[] getParameterTypes();
public abstract int getModifiers();
public abstract Class<?>[] getParameterTypes();
public abstract Class<?>[] getExceptionTypes();
public abstract Type[] getGenericExceptionTypes();
public abstract Type[] getGenericParameterTypes();
public abstract Annotation[][] getParameterAnnotations();
public abstract boolean isVarArgs();
public abstract String toGenericString();

/**
* @return the name used in the head of the string returned from inspect()
*/
@@ -82,14 +91,8 @@ public final RubyFixnum arity() {
return getRuntime().newFixnum(getArity());
}

@JRubyMethod
public final RubyArray argument_types() {
return toRubyArray(getRuntime(), getParameterTypes());
}

// same as argument_types, but matches name in java.lang.reflect.Constructor/Method
@JRubyMethod
public RubyArray parameter_types() {
@JRubyMethod(name = { "argument_types", "parameter_types" })
public final RubyArray parameter_types() {
return toRubyArray(getRuntime(), getParameterTypes());
}

@@ -124,59 +127,104 @@ public RubyString to_generic_string() {
}

@JRubyMethod
public IRubyObject inspect() {
StringBuilder result = new StringBuilder();
result.append(nameOnInspection());
Class<?>[] parameterTypes = getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
result.append(parameterTypes[i].getName());
if (i < parameterTypes.length - 1) {
result.append(',');
}
public RubyString inspect() {
StringBuilder str = new StringBuilder();
str.append( nameOnInspection() );
dumpParameterTypes(str, false);
str.append(")>");
return getRuntime().newString( str.toString() );
}

private CharSequence dumpParameterTypes(final StringBuilder str, final boolean brackets) {
if ( brackets ) str.append('[');
final Class<?>[] types = parameterTypes;
for ( int i = 0; i < types.length; i++ ) {
str.append( types[i].getName() );
if ( i < types.length - 1 ) str.append(',');
}
result.append(")>");
return getRuntime().newString(result.toString());
if ( brackets ) str.append(']');
return str;
}


@JRubyMethod(name = "public?")
public RubyBoolean public_p() {
return RubyBoolean.newBoolean(getRuntime(), Modifier.isPublic(getModifiers()));
}

protected void checkArity(int length) {
if (length != getArity()) {
protected final void checkArity(final int length) {
if ( length != getArity() ) {
throw getRuntime().newArgumentError(length, getArity());
}
}

protected static String dumpArgTypes(Object[] arguments) {
StringBuilder str = new StringBuilder("[");
for (int i = 0; i < arguments.length; i++) {
if (i > 0) {
str.append(",");
}
if (arguments[i] == null) {
str.append("null");
} else {
str.append(arguments[i].getClass().getName());
}
final Object[] convertArguments(final IRubyObject[] args) {
return convertArguments(args, 0);
}

final Object[] convertArguments(final IRubyObject[] args, int offset) {
final Object[] arguments = new Object[ args.length - offset ];
final Class<?>[] types = parameterTypes;
for ( int i = arguments.length; --i >= 0; ) {
arguments[i] = args[ i + offset ].toJava( types[i] );
}
str.append("]");
return str.toString();
return arguments;
}

protected IRubyObject handleThrowable(ThreadContext context, Throwable t) {
protected final IRubyObject handleThrowable(ThreadContext context, final Throwable ex) {
if (REWRITE_JAVA_TRACE) {
Helpers.rewriteStackTraceAndThrow(context, t);
Helpers.rewriteStackTraceAndThrow(context, ex);
}

Helpers.throwException(t);
// not reached
return getRuntime().getNil();
Helpers.throwException(ex);
return null; // not reached
}

protected IRubyObject handleInvocationTargetEx(ThreadContext context, InvocationTargetException ite) {
return handleThrowable(context, ite.getTargetException());
protected final IRubyObject handleInvocationTargetEx(ThreadContext context, InvocationTargetException ex) {
return handleThrowable(context, ex.getTargetException());
}

final IRubyObject handleIllegalAccessEx(final IllegalAccessException ex, Member target) throws RaiseException {
throw getRuntime().newTypeError("illegal access on '" + target.getName() + "': " + ex.getMessage());
}

final IRubyObject handleIllegalAccessEx(final IllegalAccessException ex, Constructor target) throws RaiseException {
throw getRuntime().newTypeError("illegal access on constructor for type '" + target.getDeclaringClass().getSimpleName() + "': " + ex.getMessage());
}

final IRubyObject handlelIllegalArgumentEx(final IllegalArgumentException ex, Method target, Object... arguments) throws RaiseException {
final StringBuilder msg = new StringBuilder(64);
msg.append("for method ").append( target.getDeclaringClass().getSimpleName() )
.append('.').append( target.getName() );
msg.append(" expected "); dumpParameterTypes(msg, true);
msg.append("; got: "); dumpArgTypes(arguments, msg);
msg.append("; error: ").append( ex.getMessage() );
throw getRuntime().newTypeError( msg.toString() );
}

final IRubyObject handlelIllegalArgumentEx(final IllegalArgumentException ex, Constructor target, Object... arguments) throws RaiseException {
return handlelIllegalArgumentEx(ex, target, true, arguments);
}

final IRubyObject handlelIllegalArgumentEx(final IllegalArgumentException ex, Constructor target, final boolean targetInfo, Object... arguments) throws RaiseException {
final StringBuilder msg = new StringBuilder(64);
if ( targetInfo ) {
msg.append("for constructor of type ").append( target.getDeclaringClass().getSimpleName() );
}
msg.append(" expected "); dumpParameterTypes(msg, true);
msg.append("; got: "); dumpArgTypes(arguments, msg);
msg.append("; error: ").append( ex.getMessage() );
throw getRuntime().newTypeError( msg.toString() );
}

static CharSequence dumpArgTypes(final Object[] args, final StringBuilder str) {
str.append('[');
for ( int i = 0; i < args.length; i++ ) {
if ( i > 0 ) str.append(',');
if ( args[i] == null ) str.append("null");
else str.append( args[i].getClass().getName() );
}
str.append(']');
return str;
}

}
153 changes: 82 additions & 71 deletions core/src/main/java/org/jruby/javasupport/JavaClass.java
Original file line number Diff line number Diff line change
@@ -64,34 +64,32 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import org.jruby.util.CodegenUtils;

@JRubyClass(name="Java::JavaClass", parent="Java::JavaObject")
public class JavaClass extends JavaObject {

// caching constructors, as they're accessed for each new instance
private volatile RubyArray constructors;

public RubyModule getProxyModule() {
return Java.getProxyClass(getRuntime(), (Class)getValue());
}

public RubyClass getProxyClass() {
return (RubyClass)Java.getProxyClass(getRuntime(), (Class)getValue());
}

public JavaClass(final Ruby runtime, final Class<?> javaClass) {
super(runtime, runtime.getJavaSupport().getJavaClassClass(), javaClass);
}

@Override
public boolean equals(Object other) {
return other instanceof JavaClass &&
this.getValue() == ((JavaClass) other).getValue();
public final boolean equals(Object other) {
if ( this == other ) return true;
return other instanceof JavaClass && this.getValue() == ((JavaClass) other).getValue();
}

@Override
public int hashCode() {
return javaClass().hashCode();
public final int hashCode() {
return getValue().hashCode();
}

public final RubyModule getProxyModule() {
return Java.getProxyClass(getRuntime(), javaClass());
}

public final RubyClass getProxyClass() {
return (RubyClass) Java.getProxyClass(getRuntime(), javaClass());
}

public void addProxyExtender(final IRubyObject extender) {
@@ -133,26 +131,30 @@ static RubyArray toRubyArray(final Ruby runtime, final Class<?>[] classes) {
return RubyArray.newArrayNoCopy(runtime, javaClasses);
}

public static RubyClass createJavaClassClass(Ruby runtime, RubyModule javaModule) {
public static RubyClass createJavaClassClass(final Ruby runtime, final RubyModule Java) {
return createJavaClassClass(runtime, Java, Java.getClass("JavaObject"));
}

static RubyClass createJavaClassClass(final Ruby runtime, final RubyModule Java, final RubyClass JavaObject) {
// FIXME: Determine if a real allocator is needed here. Do people want to extend
// JavaClass? Do we want them to do that? Can you Class.new(JavaClass)? Should
// you be able to?
// TODO: NOT_ALLOCATABLE_ALLOCATOR is probably ok here, since we don't intend for people to monkey with
// this type and it can't be marshalled. Confirm. JRUBY-415
RubyClass result = javaModule.defineClassUnder("JavaClass", javaModule.getClass("JavaObject"), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
RubyClass JavaCLass = Java.defineClassUnder("JavaClass", JavaObject, ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);

result.includeModule(runtime.getModule("Comparable"));
JavaCLass.includeModule(runtime.getModule("Comparable"));

result.defineAnnotatedMethods(JavaClass.class);
JavaCLass.defineAnnotatedMethods(JavaClass.class);

result.getMetaClass().undefineMethod("new");
result.getMetaClass().undefineMethod("allocate");
JavaCLass.getMetaClass().undefineMethod("new");
JavaCLass.getMetaClass().undefineMethod("allocate");

return result;
return JavaCLass;
}

public Class javaClass() {
return (Class) getValue();
public final Class javaClass() {
return (Class<?>) getValue();
}

public static Class<?> getJavaClass(final ThreadContext context, final RubyModule proxy) {
@@ -271,8 +273,8 @@ public RubyString name() {
return getRuntime().newString(javaClass().getName());
}

@JRubyMethod
@Override
@JRubyMethod
public RubyString inspect() {
return getRuntime().newString("class " + javaClass().getName());
}
@@ -332,11 +334,13 @@ public IRubyObject resource_as_string(IRubyObject name) {

@SuppressWarnings("unchecked")
@JRubyMethod(required = 1)
public IRubyObject annotation(IRubyObject annoClass) {
if (!(annoClass instanceof JavaClass)) {
throw getRuntime().newTypeError(annoClass, getRuntime().getJavaSupport().getJavaClassClass());
public IRubyObject annotation(final IRubyObject annoClass) {
final Ruby runtime = getRuntime();
if ( ! ( annoClass instanceof JavaClass ) ) {
throw runtime.newTypeError(annoClass, runtime.getJavaSupport().getJavaClassClass());
}
return Java.getInstance(getRuntime(), javaClass().getAnnotation(((JavaClass) annoClass).javaClass()));
final Class annotation = ((JavaClass) annoClass).javaClass();
return Java.getInstance(runtime, javaClass().getAnnotation(annotation));
}

@JRubyMethod
@@ -365,11 +369,13 @@ public RubyBoolean declared_annotations_p() {

@SuppressWarnings("unchecked")
@JRubyMethod(name = "annotation_present?", required = 1)
public IRubyObject annotation_present_p(IRubyObject annoClass) {
if (!(annoClass instanceof JavaClass)) {
throw getRuntime().newTypeError(annoClass, getRuntime().getJavaSupport().getJavaClassClass());
public IRubyObject annotation_present_p(final IRubyObject annoClass) {
final Ruby runtime = getRuntime();
if ( ! ( annoClass instanceof JavaClass ) ) {
throw runtime.newTypeError(annoClass, runtime.getJavaSupport().getJavaClassClass());
}
return getRuntime().newBoolean(javaClass().isAnnotationPresent(((JavaClass)annoClass).javaClass()));
final Class annotation = ((JavaClass) annoClass).javaClass();
return runtime.newBoolean( javaClass().isAnnotationPresent(annotation) );
}

@JRubyMethod
@@ -468,28 +474,29 @@ public IRubyObject superclass() {

@JRubyMethod(name = "<=>", required = 1)
public IRubyObject op_cmp(IRubyObject other) {
Class me = javaClass();
Class them = null;
final Class<?> thisClass = javaClass();
Class<?> otherClass = null;

// dig out the other class
if (other instanceof JavaClass) {
JavaClass otherClass = (JavaClass) other;
them = otherClass.javaClass();
} else if (other instanceof ConcreteJavaProxy) {
ConcreteJavaProxy proxy = (ConcreteJavaProxy)other;
if (proxy.getObject() instanceof Class) {
them = (Class)proxy.getObject();
otherClass = ( (JavaClass) other ).javaClass();
}
else if (other instanceof ConcreteJavaProxy) {
ConcreteJavaProxy proxy = (ConcreteJavaProxy) other;
final Object wrapped = proxy.getObject();
if ( wrapped instanceof Class ) {
otherClass = (Class) wrapped;
}
}

if (them != null) {
if (this.javaClass() == them) {
if ( otherClass != null ) {
if ( thisClass == otherClass ) {
return getRuntime().newFixnum(0);
}
if (them.isAssignableFrom(me)) {
if ( otherClass.isAssignableFrom(thisClass) ) {
return getRuntime().newFixnum(-1);
}
if (me.isAssignableFrom(them)) {
if ( thisClass.isAssignableFrom(otherClass) ) {
return getRuntime().newFixnum(1);
}
}
@@ -607,6 +614,9 @@ private static Class<?>[] buildArgumentTypes(final Ruby runtime,
return argumentTypes;
}

// caching constructors, as they're accessed for each new instance
private volatile RubyArray constructors; // TODO seems not used that often?

@JRubyMethod
public RubyArray constructors() {
final RubyArray constructors = this.constructors;
@@ -877,43 +887,44 @@ public RubyArray interfaces() {

@JRubyMethod(name = "primitive?")
public RubyBoolean primitive_p() {
return getRuntime().newBoolean(isPrimitive());
return getRuntime().newBoolean( isPrimitive() );
}

boolean isPrimitive() { return javaClass().isPrimitive(); }

@JRubyMethod(name = "assignable_from?", required = 1)
public RubyBoolean assignable_from_p(IRubyObject other) {
if (! (other instanceof JavaClass)) {
if ( ! (other instanceof JavaClass) ) {
throw getRuntime().newTypeError("assignable_from requires JavaClass (" + other.getType() + " given)");
}

Class<?> otherClass = ((JavaClass) other).javaClass();
return assignable(javaClass(), otherClass) ? getRuntime().getTrue() : getRuntime().getFalse();
return isAssignableFrom(otherClass) ? getRuntime().getTrue() : getRuntime().getFalse();
}

public final boolean isAssignableFrom(final Class<?> clazz) {
return assignable(javaClass(), clazz);
}

public static boolean assignable(Class<?> thisClass, Class<?> otherClass) {
if(!thisClass.isPrimitive() && otherClass == Void.TYPE ||
thisClass.isAssignableFrom(otherClass)) {
public static boolean assignable(Class<?> target, Class<?> from) {
if ( target.isPrimitive() ) target = CodegenUtils.getBoxType(target);
else if ( from == Void.TYPE || target.isAssignableFrom(from) ) {
return true;
}
if ( from.isPrimitive() ) from = CodegenUtils.getBoxType(from);

otherClass = JavaUtil.primitiveToWrapper(otherClass);
thisClass = JavaUtil.primitiveToWrapper(thisClass);
if ( target.isAssignableFrom(from) ) return true;

if(thisClass.isAssignableFrom(otherClass)) {
return true;
}
if(Number.class.isAssignableFrom(thisClass)) {
if(Number.class.isAssignableFrom(otherClass)) {
if ( Number.class.isAssignableFrom(target) ) {
if ( Number.class.isAssignableFrom(from) ) {
return true;
}
if(otherClass.equals(Character.class)) {
if ( from == Character.class ) {
return true;
}
}
if(thisClass.equals(Character.class)) {
if(Number.class.isAssignableFrom(otherClass)) {
else if ( target == Character.class ) {
if ( Number.class.isAssignableFrom(from) ) {
return true;
}
}
@@ -928,16 +939,16 @@ public JavaClass component_type() {
return JavaClass.get(getRuntime(), javaClass().getComponentType());
}

public static Constructor[] getConstructors(Class<?> javaClass) {
public static Constructor[] getConstructors(final Class<?> clazz) {
try {
return javaClass.getConstructors();
return clazz.getConstructors();
}
catch (SecurityException e) { return new Constructor[0]; }
}

public static Class<?>[] getDeclaredClasses(Class<?> javaClass) {
public static Class<?>[] getDeclaredClasses(final Class<?> clazz) {
try {
return javaClass.getDeclaredClasses();
return clazz.getDeclaredClasses();
}
catch (SecurityException e) { return new Class<?>[0]; }
catch (NoClassDefFoundError cnfe) {
@@ -949,18 +960,18 @@ public static Class<?>[] getDeclaredClasses(Class<?> javaClass) {
}
}

public static Field[] getDeclaredFields(Class<?> javaClass) {
public static Field[] getDeclaredFields(final Class<?> clazz) {
try {
return javaClass.getDeclaredFields();
return clazz.getDeclaredFields();
}
catch (SecurityException e) {
return getFields(javaClass);
return getFields(clazz);
}
}

public static Field[] getFields(Class<?> javaClass) {
public static Field[] getFields(final Class<?> clazz) {
try {
return javaClass.getFields();
return clazz.getFields();
}
catch (SecurityException e) { return new Field[0]; }
}
198 changes: 81 additions & 117 deletions core/src/main/java/org/jruby/javasupport/JavaConstructor.java
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@
* Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
* Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
* Copyright (C) 2004 David Corbin <dcorbin@users.sourceforge.net>
*
*
* 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"),
@@ -51,12 +51,11 @@

@JRubyClass(name="Java::JavaConstructor")
public class JavaConstructor extends JavaCallable {

private final Constructor<?> constructor;
private final JavaUtil.JavaConverter objectConverter;
//private final JavaUtil.JavaConverter objectConverter;

public Object getValue() {
return constructor;
}
public final Constructor getValue() { return constructor; }

public static RubyClass createJavaConstructorClass(Ruby runtime, RubyModule javaModule) {
// TODO: NOT_ALLOCATABLE_ALLOCATOR is probably ok here, since we don't intend for people to monkey with
@@ -66,116 +65,118 @@ public static RubyClass createJavaConstructorClass(Ruby runtime, RubyModule java

JavaAccessibleObject.registerRubyMethods(runtime, result);
JavaCallable.registerRubyMethods(runtime, result);

result.defineAnnotatedMethods(JavaConstructor.class);

return result;
}

public JavaConstructor(Ruby runtime, Constructor<?> constructor) {
super(runtime, runtime.getJavaSupport().getJavaConstructorClass(), constructor.getParameterTypes());
this.constructor = constructor;

this.objectConverter = JavaUtil.getJavaConverter(constructor.getDeclaringClass());
//this.objectConverter = JavaUtil.getJavaConverter(constructor.getDeclaringClass());
}

public static JavaConstructor create(Ruby runtime, Constructor<?> constructor) {
return new JavaConstructor(runtime, constructor);
}

public static JavaConstructor getMatchingConstructor(Ruby runtime, Class<?> javaClass, Class<?>[] argumentTypes) {

public static JavaConstructor getMatchingConstructor(final Ruby runtime,
final Class<?> javaClass, final Class<?>[] argumentTypes) {
try {
return create(runtime, javaClass.getConstructor(argumentTypes));
} catch (NoSuchMethodException e) {
}
catch (NoSuchMethodException e) {
final int argLength = argumentTypes.length;
// Java reflection does not allow retrieving constructors like methods
CtorSearch: for (Constructor<?> ctor : javaClass.getConstructors()) {
Class<?>[] targetTypes = ctor.getParameterTypes();

Search: for (Constructor<?> ctor : javaClass.getConstructors()) {
final Class<?>[] ctorTypes = ctor.getParameterTypes();
final int ctorLength = ctorTypes.length;

if ( ctorLength != argLength ) continue Search;
// for zero args case we can stop searching
if (targetTypes.length != argumentTypes.length) {
continue CtorSearch;
} else if (targetTypes.length == 0 && argumentTypes.length == 0) {
if ( ctorLength == 0 && argLength == 0 ) {
return create(runtime, ctor);
} else {
boolean found = true;

TypeScan: for (int i = 0; i < argumentTypes.length; i++) {
if (i >= targetTypes.length) found = false;

if (targetTypes[i].isAssignableFrom(argumentTypes[i])) {
found = true;
continue TypeScan;
} else {
found = false;
continue CtorSearch;
}
}
}

// if we get here, we found a matching method, use it
// TODO: choose narrowest method by continuing to search
if (found) {
return create(runtime, ctor);
boolean found = true;
TypeScan: for ( int i = 0; i < argLength; i++ ) {
//if ( i >= ctorLength ) found = false;
if ( ctorTypes[i].isAssignableFrom(argumentTypes[i]) ) {
found = true; // continue TypeScan;
} else {
continue Search; // not-found
}
}

// if we get here, we found a matching method, use it
// TODO: choose narrowest method by continuing to search
if ( found ) return create(runtime, ctor);
}
}
// no matching ctor found
return null;
return null; // no matching ctor found
}

public boolean equals(Object other) {
public final boolean equals(Object other) {
return other instanceof JavaConstructor &&
this.constructor == ((JavaConstructor)other).constructor;
this.constructor.equals( ((JavaConstructor) other).constructor );
}
public int hashCode() {

public final int hashCode() {
return constructor.hashCode();
}

public int getArity() {
return parameterTypes.length;
}

protected String nameOnInspection() {
return getType().toString();
}

public Class<?>[] getParameterTypes() {
return parameterTypes;
}
//@Override
//public final int getArity() {
// return parameterTypes.length;
//}

//@Override
//public final Class<?>[] getParameterTypes() {
// return parameterTypes;
//}

public Class<?>[] getExceptionTypes() {
@Override
public final Class<?>[] getExceptionTypes() {
return constructor.getExceptionTypes();
}

@Override
public Type[] getGenericParameterTypes() {
return constructor.getGenericParameterTypes();
}

@Override
public Type[] getGenericExceptionTypes() {
return constructor.getGenericExceptionTypes();
}

public Annotation[][] getParameterAnnotations() {
return constructor.getParameterAnnotations();
}

public boolean isVarArgs() {

@Override
public final boolean isVarArgs() {
return constructor.isVarArgs();
}

public int getModifiers() {
@Override
public final int getModifiers() {
return constructor.getModifiers();
}

public String toGenericString() {
return constructor.toGenericString();
}

public AccessibleObject accessibleObject() {
return constructor;
}

@JRubyMethod
public IRubyObject type_parameters() {
return Java.getInstance(getRuntime(), constructor.getTypeParameters());
@@ -187,52 +188,30 @@ public IRubyObject return_type() {
}

@JRubyMethod(rest = true)
public IRubyObject new_instance(IRubyObject[] args) {
int length = args.length;
Class<?>[] types = parameterTypes;
if (length != types.length) {
throw getRuntime().newArgumentError(length, types.length);
}
Object[] constructorArguments = new Object[length];
for (int i = length; --i >= 0; ) {
constructorArguments[i] = args[i].toJava(types[i]);
}
try {
Object result = constructor.newInstance(constructorArguments);
return JavaObject.wrap(getRuntime(), result);

} catch (IllegalArgumentException iae) {
throw getRuntime().newTypeError("expected " + argument_types().inspect() +
", got [" + constructorArguments[0].getClass().getName() + ", ...]");
} catch (IllegalAccessException iae) {
throw getRuntime().newTypeError("illegal access");
} catch (InvocationTargetException ite) {
getRuntime().getJavaSupport().handleNativeException(ite.getTargetException(), constructor);
// not reached
assert false;
return null;
} catch (InstantiationException ie) {
throw getRuntime().newTypeError("can't make instance of " + constructor.getDeclaringClass().getName());
}
public final IRubyObject new_instance(final IRubyObject[] args) {
return new_instance( convertArguments(args) );
}

public IRubyObject new_instance(Object[] arguments) {
public final IRubyObject new_instance(final Object[] arguments) {
checkArity(arguments.length);

try {
Object result = constructor.newInstance(arguments);
return JavaObject.wrap(getRuntime(), result);
} catch (IllegalArgumentException iae) {
throw getRuntime().newTypeError("expected " + argument_types().inspect() +
", got [" + arguments[0].getClass().getName() + ", ...]");
} catch (IllegalAccessException iae) {
}
catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(iae, constructor, false, arguments);
}
catch (IllegalAccessException iae) {
throw getRuntime().newTypeError("illegal access");
} catch (InvocationTargetException ite) {
}
catch (InvocationTargetException ite) {
getRuntime().getJavaSupport().handleNativeException(ite.getTargetException(), constructor);
// not reached
assert false;
return null;
} catch (InstantiationException ie) {
}
catch (InstantiationException ie) {
throw getRuntime().newTypeError("can't make instance of " + constructor.getDeclaringClass().getName());
}
}
@@ -243,9 +222,9 @@ public Object newInstanceDirect(ThreadContext context, Object... arguments) {
try {
return constructor.newInstance(arguments);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(iae, arguments);
return handlelIllegalArgumentEx(iae, constructor, arguments);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(iae);
return handleIllegalAccessEx(iae, constructor);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -259,9 +238,9 @@ public Object newInstanceDirect(ThreadContext context) {
try {
return constructor.newInstance();
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(iae);
return handlelIllegalArgumentEx(iae, constructor);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(iae);
return handleIllegalAccessEx(iae, constructor);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -275,9 +254,9 @@ public Object newInstanceDirect(ThreadContext context, Object arg0) {
try {
return constructor.newInstance(arg0);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(iae, arg0);
return handlelIllegalArgumentEx(iae, constructor, arg0);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(iae);
return handleIllegalAccessEx(iae, constructor);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -291,9 +270,9 @@ public Object newInstanceDirect(ThreadContext context, Object arg0, Object arg1)
try {
return constructor.newInstance(arg0, arg1);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(iae, arg0, arg1);
return handlelIllegalArgumentEx(iae, constructor, arg0, arg1);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(iae);
return handleIllegalAccessEx(iae, constructor);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -307,9 +286,9 @@ public Object newInstanceDirect(ThreadContext context, Object arg0, Object arg1,
try {
return constructor.newInstance(arg0, arg1, arg2);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(iae, arg0, arg1, arg2);
return handlelIllegalArgumentEx(iae, constructor, arg0, arg1, arg2);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(iae);
return handleIllegalAccessEx(iae, constructor);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -323,29 +302,14 @@ public Object newInstanceDirect(ThreadContext context, Object arg0, Object arg1,
try {
return constructor.newInstance(arg0, arg1, arg2, arg3);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(iae, arg0, arg1, arg2, arg3);
return handlelIllegalArgumentEx(iae, constructor, arg0, arg1, arg2, arg3);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(iae);
return handleIllegalAccessEx(iae, constructor);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
return handleThrowable(context, t);
}
}

private IRubyObject handleIllegalAccessEx(IllegalAccessException iae) {
throw getRuntime().newTypeError("illegal access on constructor for type " + constructor.getDeclaringClass().getSimpleName() + ": " + iae.getMessage());
}

private IRubyObject handlelIllegalArgumentEx(IllegalArgumentException iae, Object... arguments) {
throw getRuntime().newTypeError(
"for constructor of type " +
constructor.getDeclaringClass().getSimpleName() +
" expected " +
argument_types().inspect() +
"; got: " +
dumpArgTypes(arguments) +
"; error: " +
iae.getMessage());
}

}
20 changes: 10 additions & 10 deletions core/src/main/java/org/jruby/javasupport/JavaEmbedUtils.java
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
* rights and limitations under the License.
*
* Copyright (C) 2006 Thomas E Enebo <enebo@acm.org>
*
*
* 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"),
@@ -60,11 +60,11 @@
public class JavaEmbedUtils {
/**
* Get an instance of a JRuby runtime. Provide any loadpaths you want used at startup.
*
* @param loadPaths to specify where to look for Ruby modules.
*
* @param loadPaths to specify where to look for Ruby modules.
* @return an instance
*/
public static Ruby initialize(List loadPaths) {
public static Ruby initialize(List<String> loadPaths) {
return initialize(loadPaths, new RubyInstanceConfig());
}

@@ -74,9 +74,9 @@ public static Ruby initialize(List loadPaths) {
* @param config a runtime configuration instance
* @return an instance
*/
public static Ruby initialize(List loadPaths, RubyInstanceConfig config) {
public static Ruby initialize(List<String> loadPaths, RubyInstanceConfig config) {
Ruby runtime = Ruby.newInstance(config);
runtime.getLoadService().addPaths((List<String>)loadPaths);
runtime.getLoadService().addPaths(loadPaths);
runtime.getLoadService().require("java");

return runtime;
@@ -204,7 +204,7 @@ public IRubyObject run() {

/**
* Dispose of the runtime you initialized.
*
*
* @param runtime to be disposed of
*/
public static void terminate(Ruby runtime) {
@@ -213,7 +213,7 @@ public static void terminate(Ruby runtime) {

/**
* Convenience function for embedders
*
*
* @param runtime environment where the invoke will occur
* @param receiver is the instance that will receive the method call
* @param method is method to be called
@@ -262,8 +262,8 @@ public static IRubyObject javaToRuby(Ruby runtime, Object value) {
if (value instanceof IRubyObject) return (IRubyObject) value;

IRubyObject result = JavaUtil.convertJavaToUsableRubyObject(runtime, value);
return result instanceof JavaObject ? Java.wrap(runtime, result) : result;

return result instanceof JavaObject ? Java.wrap(runtime, result) : result;
}

public static IRubyObject javaToRuby(Ruby runtime, boolean value) {
125 changes: 55 additions & 70 deletions core/src/main/java/org/jruby/javasupport/JavaField.java
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
* Copyright (C) 2004 David Corbin <dcorbin@users.sourceforge.net>
* Copyright (C) 2005 Charles O Nutter <headius@headius.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"),
@@ -50,19 +50,18 @@

@JRubyClass(name="Java::JavaField")
public class JavaField extends JavaAccessibleObject {
private Field field;

public Object getValue() {
return field;
}
private final Field field;

public final Field getValue() { return field; }

public static RubyClass createJavaFieldClass(Ruby runtime, RubyModule javaModule) {
// TODO: NOT_ALLOCATABLE_ALLOCATOR is probably ok here, since we don't intend for people to monkey with
// this type and it can't be marshalled. Confirm. JRUBY-415
RubyClass result = javaModule.defineClassUnder("JavaField", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);

JavaAccessibleObject.registerRubyMethods(runtime, result);

result.defineAnnotatedMethods(JavaField.class);

return result;
@@ -73,12 +72,11 @@ public JavaField(Ruby runtime, Field field) {
this.field = field;
}

public boolean equals(Object other) {
return other instanceof JavaField &&
this.field == ((JavaField)other).field;
public final boolean equals(Object other) {
return other instanceof JavaField && this.field.equals( ((JavaField) other).field );
}
public int hashCode() {

public final int hashCode() {
return field.hashCode();
}

@@ -87,15 +85,6 @@ public RubyString value_type() {
return getRuntime().newString(field.getType().getName());
}

@JRubyMethod(name = {"==", "==="})
public IRubyObject op_equal(IRubyObject other) {
if (!(other instanceof JavaField)) {
return getRuntime().getFalse();
}

return getRuntime().newBoolean(field.equals(((JavaField) other).field));
}

@JRubyMethod(name = "public?")
public RubyBoolean public_p() {
return getRuntime().newBoolean(Modifier.isPublic(field.getModifiers()));
@@ -105,7 +94,7 @@ public RubyBoolean public_p() {
public RubyBoolean static_p() {
return getRuntime().newBoolean(Modifier.isStatic(field.getModifiers()));
}

@JRubyMethod(name = "enum_constant?")
public RubyBoolean enum_constant_p() {
return getRuntime().newBoolean(field.isEnumConstant());
@@ -115,7 +104,7 @@ public RubyBoolean enum_constant_p() {
public RubyString to_generic_string() {
return getRuntime().newString(field.toGenericString());
}

@JRubyMethod(name = "type")
public IRubyObject field_type() {
return JavaClass.get(getRuntime(), field.getType());
@@ -126,39 +115,35 @@ public IRubyObject value(ThreadContext context, IRubyObject object) {
Ruby runtime = context.runtime;

Object javaObject = null;
if (!Modifier.isStatic(field.getModifiers())) {
if ( ! Modifier.isStatic( field.getModifiers() ) ) {
javaObject = JavaUtil.unwrapJavaValue(runtime, object, "not a java object");
}
try {
return JavaUtil.convertJavaToUsableRubyObject(runtime, field.get(javaObject));
} catch (IllegalAccessException iae) {
return convertToRuby(runtime, field.get(javaObject));
}
catch (IllegalAccessException iae) {
throw runtime.newTypeError("illegal access");
}
}

@JRubyMethod
public IRubyObject set_value(IRubyObject object, IRubyObject value) {
Object javaObject = null;
if (!Modifier.isStatic(field.getModifiers())) {
if ( ! Modifier.isStatic( field.getModifiers() ) ) {
javaObject = JavaUtil.unwrapJavaValue(getRuntime(), object, "not a java object: " + object);
}
IRubyObject val = value;
if(val.dataGetStruct() instanceof JavaObject) {
val = (IRubyObject)val.dataGetStruct();
}
final Object javaValue = convertValueToJava(value);
try {
Object convertedValue = val.toJava(field.getType());

field.set(javaObject, convertedValue);
} catch (IllegalAccessException iae) {
throw getRuntime().newTypeError(
"illegal access on setting variable: " + iae.getMessage());
} catch (IllegalArgumentException iae) {
throw getRuntime().newTypeError(
"wrong type for " + field.getType().getName() + ": " +
val.getClass().getName());
field.set(javaObject, javaValue);
}
catch (IllegalAccessException iae) {
throw getRuntime().newTypeError("illegal access on setting variable: " + iae.getMessage());
}
return val;
catch (IllegalArgumentException iae) {
throw getRuntime().newTypeError("wrong type for " + field.getType().getName() + ": " +
( javaValue == null ? null : javaValue.getClass().getName() ) );
}
return value;
}

@JRubyMethod(name = "final?")
@@ -167,53 +152,53 @@ public RubyBoolean final_p() {
}

@JRubyMethod
public JavaObject static_value() {
public IRubyObject static_value() {
try {
// TODO: Only setAccessible to account for pattern found by
// accessing constants included from a non-public interface.
// (aka java.util.zip.ZipConstants being implemented by many
// classes)
if (!Ruby.isSecurityRestricted()) {
field.setAccessible(true);
}
return JavaObject.wrap(getRuntime(), field.get(null));
} catch (IllegalAccessException iae) {
return convertToRuby( getRuntime(), field.get(null) );
}
catch (IllegalAccessException iae) {
throw getRuntime().newTypeError("illegal static value access: " + iae.getMessage());
}
}

@JRubyMethod
public JavaObject set_static_value(IRubyObject value) {
if (! (value instanceof JavaObject)) {
public IRubyObject set_static_value(IRubyObject value) {
if ( ! ( value instanceof JavaObject ) ) {
throw getRuntime().newTypeError("not a java object:" + value);
}
final Object javaValue = convertValueToJava(value);
try {
Object convertedValue = value.toJava(field.getType());
// TODO: Only setAccessible to account for pattern found by
// accessing constants included from a non-public interface.
// (aka java.util.zip.ZipConstants being implemented by many
// classes)
// TODO: not sure we need this at all, since we only expose
// public fields.
//field.setAccessible(true);
field.set(null, convertedValue);
} catch (IllegalAccessException iae) {
field.set(null, javaValue);
}
catch (IllegalAccessException iae) {
throw getRuntime().newTypeError(
"illegal access on setting static variable: " + iae.getMessage());
} catch (IllegalArgumentException iae) {
throw getRuntime().newTypeError(
"wrong type for " + field.getType().getName() + ": " +
((JavaObject) value).getValue().getClass().getName());
}
return (JavaObject) value;
catch (IllegalArgumentException iae) {
throw getRuntime().newTypeError("wrong type for " + field.getType().getName() + ": " +
( javaValue == null ? null : javaValue.getClass().getName() ) );
}
return value;
}

@JRubyMethod
public RubyString name() {
return getRuntime().newString(field.getName());
}


@Override
public AccessibleObject accessibleObject() {
return field;
}

private Object convertValueToJava(IRubyObject value) {
Object val = value.dataGetStruct();
if ( val instanceof JavaObject ) value = (IRubyObject) val;
return value.toJava( field.getType() );
}

private static IRubyObject convertToRuby(final Ruby runtime, final Object javaValue) {
return JavaUtil.convertJavaToUsableRubyObject(runtime, javaValue);
}

}
96 changes: 33 additions & 63 deletions core/src/main/java/org/jruby/javasupport/JavaMethod.java
Original file line number Diff line number Diff line change
@@ -65,19 +65,17 @@
@JRubyClass(name="Java::JavaMethod")
public class JavaMethod extends JavaCallable {

private static final Logger LOG = LoggerFactory.getLogger("JavaMethod");
//private static final Logger LOG = LoggerFactory.getLogger("JavaMethod");

private final static boolean USE_HANDLES = RubyInstanceConfig.USE_GENERATED_HANDLES;
private final static boolean HANDLE_DEBUG = false;
//private final static boolean USE_HANDLES = RubyInstanceConfig.USE_GENERATED_HANDLES;
//private final static boolean HANDLE_DEBUG = false;

private final Method method;
private final Class<?> boxedReturnType;
private final boolean isFinal;
private final JavaUtil.JavaConverter returnConverter;

public Object getValue() {
return method;
}
public final Method getValue() { return method; }

public static RubyClass createJavaMethodClass(Ruby runtime, RubyModule javaModule) {
// TODO: NOT_ALLOCATABLE_ALLOCATOR is probably ok here, since we don't intend for people to monkey with
@@ -186,13 +184,12 @@ public static JavaMethod getMatchingDeclaredMethod(Ruby runtime, Class<?> javaCl
}

@Override
public boolean equals(Object other) {
return other instanceof JavaMethod &&
this.method == ((JavaMethod)other).method;
public final boolean equals(Object other) {
return other instanceof JavaMethod && this.method.equals( ((JavaMethod)other).method );
}

@Override
public int hashCode() {
public final int hashCode() {
return method.hashCode();
}

@@ -202,11 +199,6 @@ public RubyString name() {
return getRuntime().newString(method.getName());
}

@Override
public int getArity() {
return parameterTypes.length;
}

@JRubyMethod(name = "public?")
@Override
public RubyBoolean public_p() {
@@ -393,9 +385,9 @@ private IRubyObject invokeWithExceptionHandling(ThreadContext context, Method me
Object result = method.invoke(javaInvokee, arguments);
return returnConverter.convert(getRuntime(), result);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(method, iae, arguments);
return handlelIllegalArgumentEx(iae, method, arguments);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(method, iae);
return handleIllegalAccessEx(iae, method);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -410,9 +402,9 @@ private IRubyObject invokeDirectSuperWithExceptionHandling(ThreadContext context
Object result = method.invoke(javaInvokee, arguments);
return convertReturn(result);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(method, iae, arguments);
return handlelIllegalArgumentEx(iae, method, arguments);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(method, iae);
return handleIllegalAccessEx(iae, method);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -425,9 +417,9 @@ private IRubyObject invokeDirectWithExceptionHandling(ThreadContext context, Met
Object result = method.invoke(javaInvokee, arguments);
return convertReturn(result);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(method, iae, arguments);
return handlelIllegalArgumentEx(iae, method, arguments);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(method, iae);
return handleIllegalAccessEx(iae, method);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -440,9 +432,9 @@ private IRubyObject invokeDirectWithExceptionHandling(ThreadContext context, Met
Object result = method.invoke(javaInvokee);
return convertReturn(result);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(method, iae);
return handlelIllegalArgumentEx(iae, method);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(method, iae);
return handleIllegalAccessEx(iae, method);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -455,9 +447,9 @@ private IRubyObject invokeDirectWithExceptionHandling(ThreadContext context, Met
Object result = method.invoke(javaInvokee, arg0);
return convertReturn(result);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(method, iae, arg0);
return handlelIllegalArgumentEx(iae, method, arg0);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(method, iae);
return handleIllegalAccessEx(iae, method);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -470,9 +462,9 @@ private IRubyObject invokeDirectWithExceptionHandling(ThreadContext context, Met
Object result = method.invoke(javaInvokee, arg0, arg1);
return convertReturn(result);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(method, iae, arg0, arg1);
return handlelIllegalArgumentEx(iae, method, arg0, arg1);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(method, iae);
return handleIllegalAccessEx(iae, method);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -485,9 +477,9 @@ private IRubyObject invokeDirectWithExceptionHandling(ThreadContext context, Met
Object result = method.invoke(javaInvokee, arg0, arg1, arg2);
return convertReturn(result);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(method, iae, arg0, arg1, arg2);
return handlelIllegalArgumentEx(iae, method, arg0, arg1, arg2);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(method, iae);
return handleIllegalAccessEx(iae, method);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -500,9 +492,9 @@ private IRubyObject invokeDirectWithExceptionHandling(ThreadContext context, Met
Object result = method.invoke(javaInvokee, arg0, arg1, arg2, arg3);
return convertReturn(result);
} catch (IllegalArgumentException iae) {
return handlelIllegalArgumentEx(method, iae, arg0, arg1, arg2, arg3);
return handlelIllegalArgumentEx(iae, method, arg0, arg1, arg2, arg3);
} catch (IllegalAccessException iae) {
return handleIllegalAccessEx(method, iae);
return handleIllegalAccessEx(iae, method);
} catch (InvocationTargetException ite) {
return handleInvocationTargetEx(context, ite);
} catch (Throwable t) {
@@ -519,37 +511,15 @@ private IRubyObject convertReturn(Object result) {
return JavaUtil.convertJavaToUsableRubyObjectWithConverter(getRuntime(), result, returnConverter);
}

private IRubyObject handleIllegalAccessEx(Method method, IllegalAccessException iae) throws RaiseException {
throw getRuntime().newTypeError("illegal access on '" + method.getName() + "': " + iae.getMessage());
}
//@Override
//public final int getArity() {
// return parameterTypes.length;
//}

private IRubyObject handlelIllegalArgumentEx(Method method, IllegalArgumentException iae, Object... arguments) throws RaiseException {
throw getRuntime().newTypeError(
"for method " +
method.getDeclaringClass().getSimpleName() +
"." +
method.getName() +
" expected " +
argument_types().inspect() +
"; got: " +
dumpArgTypes(arguments) +
"; error: " +
iae.getMessage());
}

private Object[] convertArguments(final IRubyObject[] args, int offset) {
final Object[] arguments = new Object[ args.length - offset ];
final Class<?>[] types = getParameterTypes();
for ( int i = arguments.length; --i >= 0; ) {
arguments[i] = args[ i + offset ].toJava(types[i]);
}
return arguments;
}

@Override
public Class<?>[] getParameterTypes() {
return parameterTypes;
}
//@Override
//public final Class<?>[] getParameterTypes() {
// return parameterTypes;
//}

@Override
public Class<?>[] getExceptionTypes() {
@@ -572,7 +542,7 @@ public Annotation[][] getParameterAnnotations() {
}

@Override
public boolean isVarArgs() {
public final boolean isVarArgs() {
return method.isVarArgs();
}

@@ -595,7 +565,7 @@ private boolean isStatic() {
}

@Override
public int getModifiers() {
public final int getModifiers() {
return method.getModifiers();
}

18 changes: 9 additions & 9 deletions core/src/main/java/org/jruby/javasupport/JavaObject.java
Original file line number Diff line number Diff line change
@@ -65,7 +65,7 @@
public class JavaObject extends RubyObject {

private static final Object NULL_LOCK = new Object();

private final VariableAccessor objectAccessor;

protected JavaObject(Ruby runtime, RubyClass rubyClass, Object value) {
@@ -123,18 +123,18 @@ public Object getValue() {
public static RubyClass createJavaObjectClass(Ruby runtime, RubyModule javaModule) {
// FIXME: Ideally JavaObject instances should be marshallable, which means that
// the JavaObject metaclass should have an appropriate allocator. JRUBY-414
RubyClass result = javaModule.defineClassUnder("JavaObject", runtime.getObject(), JAVA_OBJECT_ALLOCATOR);
RubyClass JavaObject = javaModule.defineClassUnder("JavaObject", runtime.getObject(), JAVA_OBJECT_ALLOCATOR);

registerRubyMethods(runtime, result);
registerRubyMethods(runtime, JavaObject);

result.getMetaClass().undefineMethod("new");
result.getMetaClass().undefineMethod("allocate");
JavaObject.getMetaClass().undefineMethod("new");
JavaObject.getMetaClass().undefineMethod("allocate");

return result;
return JavaObject;
}

protected static void registerRubyMethods(Ruby runtime, RubyClass result) {
result.defineAnnotatedMethods(JavaObject.class);
protected static void registerRubyMethods(Ruby runtime, RubyClass JavaObject) {
JavaObject.defineAnnotatedMethods(JavaObject.class);
}

@Override
@@ -316,7 +316,7 @@ public Object toJava(final Class target) {
}

private static final ObjectAllocator JAVA_OBJECT_ALLOCATOR = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
public JavaObject allocate(Ruby runtime, RubyClass klazz) {
return new JavaObject(runtime, klazz, null);
}
};
1 change: 0 additions & 1 deletion core/src/main/java/org/jruby/javasupport/JavaSupport.java
Original file line number Diff line number Diff line change
@@ -40,7 +40,6 @@
import org.jruby.javasupport.proxy.JavaProxyClass;
import org.jruby.javasupport.util.ObjectProxyCache;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.collections.*;
import org.jruby.util.collections.ClassValue;

import java.lang.reflect.Member;
102 changes: 33 additions & 69 deletions core/src/main/java/org/jruby/javasupport/JavaSupportImpl.java
Original file line number Diff line number Diff line change
@@ -74,35 +74,6 @@ public IRubyObject allocateProxy(Object javaObject, RubyClass clazz) {
private final ClassValue<ThreadLocal<RubyModule>> unfinishedProxyClassCache;
private final ClassValue<Map<String, AssignedName>> staticAssignedNames;
private final ClassValue<Map<String, AssignedName>> instanceAssignedNames;
private static final Constructor<? extends ClassValue> CLASS_VALUE_CONSTRUCTOR;

static {
Constructor constructor = null;

if (Options.INVOKEDYNAMIC_CLASS_VALUES.load()) {
try {
// try to load the ClassValue class. If it succeeds, we can use our
// ClassValue-based cache.
Class.forName("java.lang.ClassValue");
constructor = Class.forName("org.jruby.util.collections.Java7ClassValue").getConstructor(ClassValueCalculator.class);
}
catch (Exception ex) {
// fall through to Map version
}
}

if (constructor == null) {
try {
constructor = MapBasedClassValue.class.getConstructor(ClassValueCalculator.class);
}
catch (Exception ex) {
if ( ex instanceof RuntimeException ) throw (RuntimeException) ex;
throw new RuntimeException(ex);
}
}

CLASS_VALUE_CONSTRUCTOR = (Constructor<ClassValue>) constructor;
}

private RubyModule javaModule;
private RubyModule javaUtilitiesModule;
@@ -122,51 +93,44 @@ public IRubyObject allocateProxy(Object javaObject, RubyClass clazz) {
private RubyClass concreteProxyClass;
private RubyClass mapJavaProxy;

private final Map<String, JavaClass> nameClassMap = new HashMap<String, JavaClass>();
private final Map<String, JavaClass> nameClassMap = new HashMap<String, JavaClass>(64);

// A cache of all JavaProxyClass objects created for this runtime
private Map<Set<?>, JavaProxyClass> javaProxyClassCache = Collections.synchronizedMap(new HashMap<Set<?>, JavaProxyClass>());

public JavaSupportImpl(final Ruby ruby) {
this.runtime = ruby;
public JavaSupportImpl(final Ruby runtime) {
this.runtime = runtime;

try {
this.javaClassCache = CLASS_VALUE_CONSTRUCTOR.newInstance(new ClassValueCalculator<JavaClass>() {
@Override
public JavaClass computeValue(Class<?> cls) {
return new JavaClass(runtime, cls);
}
});
this.proxyClassCache = CLASS_VALUE_CONSTRUCTOR.newInstance(new ClassValueCalculator<RubyModule>() {
@Override
public RubyModule computeValue(Class<?> cls) {
return Java.createProxyClassForClass(runtime, cls);
}
});
this.unfinishedProxyClassCache = CLASS_VALUE_CONSTRUCTOR.newInstance(new ClassValueCalculator<ThreadLocal<RubyModule>>() {
@Override
public ThreadLocal<RubyModule> computeValue(Class<?> cls) {
return new ThreadLocal<RubyModule>();
}
});
this.staticAssignedNames = CLASS_VALUE_CONSTRUCTOR.newInstance(new ClassValueCalculator<Map<String, AssignedName>>() {
@Override
public Map<String, AssignedName> computeValue(Class<?> cls) {
return new HashMap<String, AssignedName>();
}
});
this.instanceAssignedNames = CLASS_VALUE_CONSTRUCTOR.newInstance(new ClassValueCalculator<Map<String, AssignedName>>() {
@Override
public Map<String, AssignedName> computeValue(Class<?> cls) {
return new HashMap<String, AssignedName>();
}
});
}
catch (InstantiationException ex) { throw new RuntimeException(ex); }
catch (IllegalAccessException ex) { throw new RuntimeException(ex); }
catch (InvocationTargetException ex) {
throw new RuntimeException(ex.getTargetException());
}
this.javaClassCache = ClassValue.newInstance(new ClassValueCalculator<JavaClass>() {
@Override
public JavaClass computeValue(Class<?> cls) {
return new JavaClass(runtime, cls);
}
});
this.proxyClassCache = ClassValue.newInstance(new ClassValueCalculator<RubyModule>() {
@Override
public RubyModule computeValue(Class<?> cls) {
return Java.createProxyClassForClass(runtime, cls);
}
});
this.unfinishedProxyClassCache = ClassValue.newInstance(new ClassValueCalculator<ThreadLocal<RubyModule>>() {
@Override
public ThreadLocal<RubyModule> computeValue(Class<?> cls) {
return new ThreadLocal<RubyModule>();
}
});
this.staticAssignedNames =ClassValue.newInstance(new ClassValueCalculator<Map<String, AssignedName>>() {
@Override
public Map<String, AssignedName> computeValue(Class<?> cls) {
return new HashMap<String, AssignedName>();
}
});
this.instanceAssignedNames = ClassValue.newInstance(new ClassValueCalculator<Map<String, AssignedName>>() {
@Override
public Map<String, AssignedName> computeValue(Class<?> cls) {
return new HashMap<String, AssignedName>();
}
});
}

public Class loadJavaClass(String className) throws ClassNotFoundException {
Loading