return RuntimeHelpers.invokeSuper(context, self, clazz, block);
}
private static void appendFeaturesToClass(ThreadContext context, IRubyObject self, RubyClass clazz) {
Ruby runtime = context.getRuntime();
IRubyObject javaClassObj = self.getInstanceVariables().fastGetInstanceVariable("@java_class");
// initialize this if it hasn't been
if (javaClassObj == null) {
javaClassObj = runtime.getNil();
self.getInstanceVariables().setInstanceVariable("@java_class", javaClassObj);
}
// initialize these if they haven't been
IRubyObject javaClass = clazz.getInstanceVariables().fastGetInstanceVariable("@java_class");
if (javaClass == null) {
javaClass = runtime.getNil();
clazz.getInstanceVariables().fastSetInstanceVariable("@java_class", javaClass);
}
IRubyObject javaProxyClass = clazz.getInstanceVariables().fastGetInstanceVariable("@java_proxy_class");
if (javaProxyClass == null) {
javaProxyClass = runtime.getNil();
clazz.getInstanceVariables().fastSetInstanceVariable("@java_proxy_class", javaProxyClass);
}
// not allowed for original (non-generated) Java classes
// note: not allowing for any previously created class right now;
// this restriction might be loosened later for generated classes
if ((javaClass.isTrue() && !clazz.getSingletonClass().isMethodBound("java_proxy_class", false)) ||
javaProxyClass.isTrue()) {
throw runtime.newArgumentError("can not add Java interface to existing Java class");
}
IRubyObject javaInterfaces = clazz.getInstanceVariables().fastGetInstanceVariable("@java_interfaces");
if (javaInterfaces == null) {
javaInterfaces = RubyArray.newArray(runtime, javaClassObj);
clazz.getInstanceVariables().fastSetInstanceVariable("@java_interfaces", javaInterfaces);
// setup new, etc unless this is a ConcreteJavaProxy subclass
if (!clazz.isMethodBound("__jcreate!", false)) {
// First we make modifications to the class, to adapt it to being
// both a Ruby class and a proxy for a Java type
RubyClass singleton = clazz.getSingletonClass();
// list of interfaces we implement
singleton.addReadAttribute(context, "java_interfaces");
// We capture the original "new" and make it private
DynamicMethod newMethod = singleton.searchMethod("new").dup();
singleton.addMethod("__jredef_new", newMethod);
newMethod.setVisibility(Visibility.PRIVATE);
// The replacement "new" allocates and inits the Ruby object as before, but
// also instantiates our proxified Java object by calling __jcreate!
singleton.addMethod("new", new org.jruby.internal.runtime.methods.JavaMethod(singleton, Visibility.PUBLIC) {
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
assert self instanceof RubyClass : "new defined on non-class";
RubyClass clazzSelf = (RubyClass)self;
IRubyObject newObj = clazzSelf.allocate();
RuntimeHelpers.invoke(context, newObj, "__jcreate!", args, block);
RuntimeHelpers.invoke(context, newObj, "initialize", args, block);
return newObj;
}
});
// Next, we define a few private methods that we'll use to manipulate
// the Java object contained within this Ruby object
// jcreate instantiates the proxy object which implements all interfaces
// and which is wrapped and implemented by this object
clazz.addMethod("__jcreate!", new JavaMethodNoBlock(clazz, Visibility.PRIVATE) {
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args) {
IRubyObject javaInterfaces = RuntimeHelpers.invoke(context, self.getMetaClass(), "java_interfaces");
return jcreateProxy(self, javaInterfaces, args);
}
});
// Used by our duck-typification of Proc into interface types, to allow
// coercing a simple proc into an interface parameter.
clazz.addMethod("__jcreate_meta!", new JavaMethodNoBlock(clazz, Visibility.PRIVATE) {
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args) {
IRubyObject javaInterfaces = RuntimeHelpers.invoke(context, self.getSingletonClass(), "java_interfaces");
IRubyObject result = jcreateProxy(self, javaInterfaces, args);
return result;
}
});
clazz.includeModule(runtime.getModule("JavaProxyMethods"));
// If we hold a Java object, we need a java_class accessor
clazz.addMethod("java_class", new JavaMethodZero(clazz, Visibility.PUBLIC) {
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {