Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: CPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Common Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.eclipse.org/legal/cpl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se> Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de> Copyright (C) 2004-2005 Thomas E Enebo <enebo@acm.org> Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de> Copyright (C) 2004 David Corbin <dcorbin@users.sourceforge.net> Copyright (C) 2005 Charles O Nutter <headius@headius.com> Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org> Copyright (C) 2007 Miguel Covarrubias <mlcovarrubias@gmail.com> Copyright (C) 2007 William N Dortch <bill.dortch@gmail.com> Copyright (C) 2011 David Pollak <feeder.of.the.bears@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"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the CPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ***
  
  package org.jruby.javasupport;
  
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import org.jruby.Ruby;
  import static org.jruby.runtime.Visibility.*;
  
  @JRubyClass(name="Java::JavaClass", parent="Java::JavaObject")
 public class JavaClass extends JavaObject {
 
     private static final Logger LOG = LoggerFactory.getLogger("JavaClass");
 
     public static final String METHOD_MANGLE = "__method";
     public static final boolean DEBUG_SCALA = false;
 
     public static final boolean CAN_SET_ACCESSIBLE;
 
     static {
         boolean canSetAccessible = false;
 
         if (.) {
             try {
                 AccessController.checkPermission(new ReflectPermission("suppressAccessChecks"));
                 canSetAccessible = true;
             } catch (Throwable t) {
                 // added this so if things are weird in the future we can debug without
                 // spinning a new binary
                 if (..load()) {
                     t.printStackTrace();
                 }
 
                 // assume any exception means we can't suppress access checks
                 canSetAccessible = false;
             }
         }
 
          = canSetAccessible;
     }
 
     private void handleScalaSingletons(Class<?> javaClassInitializerState state) {
         // check for Scala companion object
         try {
             ClassLoader cl = javaClass.getClassLoader();
             if (cl == null) {
                 //this is a core class, bail
                 return;
             }
             
             Class<?> companionClass = cl.loadClass(javaClass.getName() + "$");
             Field field = companionClass.getField("MODULE$");
             Object singleton = field.get(null);
             if (singleton != null) {
                 Method[] sMethods = getMethods(companionClass);
                 for (int j = sMethods.length - 1; j >= 0; j--) {
                     Method method = sMethods[j];
                     String name = method.getName();
                     if () {
                         .debug("Companion object method {} for {}"namecompanionClass);
                     }
                     if (name.indexOf("$") >= 0) {
                         name = fixScalaNames(name);
                     }
                     if (!Modifier.isStatic(method.getModifiers())) {
                         AssignedName assignedName = state.staticNames.get(name);
                         // For JRUBY-4505, restore __method methods for reserved names
                         if (.containsKey(method.getName())) {
                             if () {
                                 .debug("in reserved " + name);
                             }
                             installSingletonMethods(state.staticCallbacksjavaClasssingletonmethodname + );
                             continue;
                         }
                         if (assignedName == null) {
                             state.staticNames.put(namenew AssignedName(name.));
                             if () {
                                 .debug("Assigned name is null");
                             }
                         } else {
                             if (..lessImportantThan(assignedName)) {
                                 if () {
                                     .debug("Less important");
                                 }
                                 continue;
                             }
                             if (!..asImportantAs(assignedName)) {
                                 state.staticCallbacks.remove(name);
                                 state.staticCallbacks.remove(name + '=');
                                 state.staticNames.put(namenew AssignedName(name.));
                             }
                         }
                         if () {
                             .debug("Installing {} {} {}"namemethodsingleton);
                         }
                         installSingletonMethods(state.staticCallbacksjavaClasssingletonmethodname);
                     } else {
                         if () {
                             .debug("Method {} is sadly static"method);
                         }
                     }
                 }
             }
             
         } catch (Exception e) {
             // ignore... there's no companion object
         }
     }
    
    
Assigned names only override based priority of an assigned type, the type must be less than or equal to the assigned type. For example, field name (FIELD) in a subclass will override an alias (ALIAS) in a superclass, but not a method (METHOD).
 
     private enum Priority {
         RESERVED(0), METHOD(1), FIELD(2), PROTECTED_METHOD(3),
         WEAKLY_RESERVED(4), ALIAS(5), PROTECTED_FIELD(6);
 
         private int value;
 
         Priority(int value) {
             this. = value;
         }
 
         public boolean asImportantAs(AssignedName other) {
             return other != null && other.type.value == ;
         }
         
         public boolean lessImportantThan(AssignedName other) {
             return other != null && other.type.value < ;
         }
         
         public boolean moreImportantThan(AssignedName other) {
             return other == null || other.type.value > ;
         }
     }
 
     private static class AssignedName {
         String name;
         Priority type;
         
         AssignedName () {}
         AssignedName(String namePriority type) {
             this. = name;
             this. = type;
         }
     }
 
     // TODO: other reserved names?
     private static final Map<StringAssignedNameRESERVED_NAMES = new HashMap<StringAssignedName>();
     static {
         .put("__id__"new AssignedName("__id__".));
         .put("__send__"new AssignedName("__send__".));
         // JRUBY-5132: java.awt.Component.instance_of?() expects 2 args
         .put("instance_of?"new AssignedName("instance_of?".));
     }
     private static final Map<StringAssignedNameSTATIC_RESERVED_NAMES = new HashMap<StringAssignedName>();
     static {
         .put("new"new AssignedName("new".));
     }
     private static final Map<StringAssignedNameINSTANCE_RESERVED_NAMES = new HashMap<StringAssignedName>();
     static {
         // only possible for "getClass" to be an instance method in Java
         .put("class"new AssignedName("class".));
         // "initialize" has meaning only for an instance (as opposed to a class)
         .put("initialize"new AssignedName("initialize".));
     }
 
     private static abstract class NamedInstaller {
         static final int STATIC_FIELD = 1;
         static final int STATIC_METHOD = 2;
         static final int INSTANCE_FIELD = 3;
         static final int INSTANCE_METHOD = 4;
         static final int CONSTRUCTOR = 5;
         String name;
         int type;
         Visibility visibility = .;
         NamedInstaller () {}
         NamedInstaller (String nameint type) {
             this. = name;
             this. = type;
         }
         abstract void install(RubyModule proxy);
         // small hack to save a cast later on
         boolean hasLocalMethod() {
             return true;
         }
         boolean isPublic() {
             return  == .;
         }
         boolean isProtected() {
             return  == .;
         }
     }
 
     private static abstract class FieldInstaller extends NamedInstaller {
         Field field;
         FieldInstaller(){}
         FieldInstaller(String nameint typeField field) {
             super(name,type);
             this. = field;
         }
     }
 
     private static class StaticFieldGetterInstaller extends FieldInstaller {
         StaticFieldGetterInstaller(){}
         StaticFieldGetterInstaller(String nameField field) {
             super(name,,field);
         }
         void install(RubyModule proxy) {
             if (Modifier.isPublic(.getModifiers())) {
                 proxy.getSingletonClass().addMethod(new StaticFieldGetter(proxy));
             }
         }
     }
 
     private static class StaticFieldSetterInstaller extends FieldInstaller {
         StaticFieldSetterInstaller(){}
         StaticFieldSetterInstaller(String nameField field) {
             super(name,,field);
         }
         void install(RubyModule proxy) {
             if (Modifier.isPublic(.getModifiers())) {
                 proxy.getSingletonClass().addMethod(new StaticFieldSetter(proxy));
             }
         }
     }
 
     private static class InstanceFieldGetterInstaller extends FieldInstaller {
         InstanceFieldGetterInstaller(){}
         InstanceFieldGetterInstaller(String nameField field) {
             super(name,,field);
         }
         void install(RubyModule proxy) {
             if (Modifier.isPublic(.getModifiers())) {
                 proxy.addMethod(new InstanceFieldGetter(proxy));
             }
         }
     }
 
     private static class InstanceFieldSetterInstaller extends FieldInstaller {
         InstanceFieldSetterInstaller(){}
         InstanceFieldSetterInstaller(String nameField field) {
             super(name,,field);
         }
         void install(RubyModule proxy) {
             if (Modifier.isPublic(.getModifiers())) {
                 proxy.addMethod(new InstanceFieldSetter(proxy));
             }
         }
     }
 
     private static abstract class MethodInstaller extends NamedInstaller {
         private boolean haveLocalMethod;
         protected List<Methodmethods;
         protected List<Stringaliases;
         MethodInstaller(){}
         MethodInstaller(String nameint type) {
             super(name,type);
         }
 
         // called only by initializing thread; no synchronization required
         void addMethod(Method methodClass<?> javaClass) {
             if ( == null) {
                  = new ArrayList<Method>(4);
             }
             .add(method);
              |= javaClass == method.getDeclaringClass() ||
                     method.getDeclaringClass().isInterface();
         }
 
         // called only by initializing thread; no synchronization required
         void addAlias(String alias) {
             if ( == null) {
                  = new ArrayList<String>(4);
             }
             if (!.contains(alias)) {
                 .add(alias);
             }
         }
 
         @Override
         boolean hasLocalMethod () {
             return ;
         }
 
         void setLocalMethod(boolean b) {
              = b;
         }
     }
 
     private static class ConstructorInvokerInstaller extends MethodInstaller {
         private boolean haveLocalConstructor;
         protected List<Constructorconstructors;
         
         ConstructorInvokerInstaller(String name) {
             super(name,);
         }
 
         // called only by initializing thread; no synchronization required
         void addConstructor(Constructor ctorClass<?> javaClass) {
             if ( == null) {
                  = new ArrayList<Constructor>(4);
             }
             if (!Ruby.isSecurityRestricted()) {
                 try {
                     ctor.setAccessible(true);
                 } catch(SecurityException e) {}
             }
             .add(ctor);
              |= javaClass == ctor.getDeclaringClass();
         }
         
         void install(final RubyModule proxy) {
             if () {
                 DynamicMethod method = new ConstructorInvoker(proxy);
                 proxy.addMethod(method);
             } else {
                 // if there's no constructor, we must prevent construction
                 proxy.addMethod(new org.jruby.internal.runtime.methods.JavaMethod(proxy) {
                     @Override
                     public IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString nameIRubyObject[] argsBlock block) {
                         throw context.runtime.newTypeError("no public constructors for " + clazz);
                     }
                 });
             }
         }
     }
 
     private static class StaticMethodInvokerInstaller extends MethodInstaller {
         StaticMethodInvokerInstaller(String name) {
             super(name,);
         }
 
         void install(RubyModule proxy) {
             if (hasLocalMethod()) {
                 RubyClass singleton = proxy.getSingletonClass();
                 DynamicMethod method = new StaticMethodInvoker(singleton);
                 singleton.addMethod(method);
                 if ( != null && isPublic() ) {
                     singleton.defineAliases(this.);
                      = null;
                 }
             }
         }
     }
 
     private static class SingletonMethodInvokerInstaller extends StaticMethodInvokerInstaller {
         private Object singleton;
 
         SingletonMethodInvokerInstaller(String nameObject singleton) {
             super(name);
             this. = singleton;
         }
 
         void install(RubyModule proxy) {
             // we don't check haveLocalMethod() here because it's not local and we know
             // that we always want to go ahead and install it
             RubyClass rubySingleton = proxy.getSingletonClass();
             DynamicMethod method = new SingletonMethodInvoker(this.rubySingleton);
             rubySingleton.addMethod(method);
             if ( != null && isPublic()) {
                 rubySingleton.defineAliases(this.);
                  = null;
             }
         }
     }
 
     private static class InstanceMethodInvokerInstaller extends MethodInstaller {
         InstanceMethodInvokerInstaller(String name) {
             super(name,);
         }
         void install(RubyModule proxy) {
             if (hasLocalMethod()) {
                 DynamicMethod method = new InstanceMethodInvoker(proxy);
                 proxy.addMethod(method);
                 if ( != null && isPublic()) {
                     proxy.defineAliases(this.);
                      = null;
                 }
             }
         }
     }
 
     private static class ConstantField {
         static final int CONSTANT = . | . | .;
         final Field field;
         ConstantField(Field field) {
             this. = field;
         }
         void install(final RubyModule proxy) {
             if (proxy.getConstantAt(.getName()) == null) {
                 // TODO: catch exception if constant is already set by other
                 // thread
                 try {
                     proxy.setConstant(.getName(), JavaUtil.convertJavaToUsableRubyObject(proxy.getRuntime(), .get(null)));
                 } catch (IllegalAccessException iae) {
                     // if we can't read it, we don't set it
                 }
             }
         }
         static boolean isConstant(final Field field) {
             return (field.getModifiers() & ) ==  &&
                 Character.isUpperCase(field.getName().charAt(0));
         }
     }
     
     
     private List<ConstantFieldconstantFields;
     // caching constructors, as they're accessed for each new instance
     private volatile RubyArray constructors;
     
     private volatile ArrayList<IRubyObjectproxyExtenders;
 
     // proxy module for interfaces
     private volatile RubyModule proxyModule;
 
     // proxy class for concrete classes.  also used for
     // "concrete" interfaces, which is why we have two fields
     private volatile RubyClass proxyClass;
 
     // readable only by thread building proxy, so don't need to be
     // volatile. used to handle recursive calls to getProxyClass/Module
     // while proxy is being constructed (usually when a constant
     // defined by a class is of the same type as that class).
     private RubyClass unfinishedProxyClass;
     
     private final ReentrantLock proxyLock = new ReentrantLock();
 
     private final Initializer initializer;
     
     public RubyModule getProxyModule() {
         // allow proxy to be read without synchronization. if proxy
         // is under construction, only the building thread can see it.
         RubyModule proxy;
         if ((proxy = ) != null) {
             // proxy is complete, return it
             return proxy;
         } else if (.isHeldByCurrentThread()) {
             // proxy is under construction, building thread can
             // safely read non-volatile value
             return 
         }
         return null;
     }
     
     public RubyClass getProxyClass() {
         // allow proxy to be read without synchronization. if proxy
         // is under construction, only the building thread can see it.
         RubyClass proxy;
         if ((proxy = ) != null) {
             // proxy is complete, return it
             return proxy;
         } else if (.isHeldByCurrentThread()) {
             // proxy is under construction, building thread can
             // safely read non-volatile value
             return 
         }
         return null;
     }
     
     public void lockProxy() {
         .lock();
     }
     
     public void unlockProxy() {
         .unlock();
     }
 
     private Map<StringAssignedNamegetStaticAssignedNames() {
         return ;
     }
         return ;
     }
     
     public JavaClass(Ruby runtimeClass<?> javaClass) {
         super(runtime, (RubyClassruntime.getJavaSupport().getJavaClassClass(), javaClass);
         if (javaClass.isInterface()) {
              = new InterfaceInitializer(javaClass);
         } else if (!(javaClass.isArray() || javaClass.isPrimitive())) {
              = new ClassInitializer(javaClass);
         } else {
              = ;
         }
     }
     
     @Override
     public boolean equals(Object other) {
         return other instanceof JavaClass &&
             this.getValue() == ((JavaClass)other).getValue();
     }
 
     @Override
     public int hashCode() {
         return javaClass().hashCode();
     }
 
     private interface Initializer {
         public void initialize();
     }
 
     private class InterfaceInitializer implements Initializer {
         private volatile boolean hasRun = false;
         private final Class javaClass;
 
         public InterfaceInitializer(Class<?> javaClass) {
             this. = javaClass;
         }
         
         public synchronized void initialize() {
             if (return;
              = true;
 
             Map<StringAssignedNamestaticNames  = new HashMap<StringAssignedName>();
             List<ConstantFieldconstants = new ArrayList<ConstantField>();
             Map<StringNamedInstallerstaticCallbacks = new HashMap<StringNamedInstaller>();
             Field[] fields = getDeclaredFields();
 
             for (int i = fields.length; --i >= 0; ) {
                 Field field = fields[i];
                 if ( != field.getDeclaringClass()) continue;
                 if (ConstantField.isConstant(field)) constants.add(new ConstantField(field));
 
                 int modifiers = field.getModifiers();
                 if (Modifier.isStatic(modifiers)) addField(staticCallbacksstaticNamesfield, Modifier.isFinal(modifiers), true);
             }
 
             // Now add all aliases for the static methods (fields) as appropriate
             for (Map.Entry<StringNamedInstallerentry : staticCallbacks.entrySet()) {
                 if (entry.getValue(). == . && entry.getValue().hasLocalMethod()) {
                     assignAliases((MethodInstaller)entry.getValue(), staticNames);
                 }
             }
 
             JavaClass.this. = staticNames;
             JavaClass.this. = staticCallbacks;
             JavaClass.this. = constants;
         }
     };
 
     private class ClassInitializer implements Initializer {
         private volatile boolean hasRun = false;
         private final Class javaClass;
 
         public ClassInitializer(Class<?> javaClass) {
             this. = javaClass;
         }
 
         public synchronized void initialize() {
             if (return;
              = true;
             
             Class<?> superclass = .getSuperclass();
 
             InitializerState state = new InitializerState(getRuntime(), superclass);
 
             setupClassFields(state);
             setupClassMethods(state);
             setupClassConstructors();
 
             JavaClass.this. = Collections.unmodifiableMap(state.staticNames);
             JavaClass.this. = Collections.unmodifiableMap(state.instanceNames);
             JavaClass.this. = Collections.unmodifiableMap(state.staticCallbacks);
             JavaClass.this. = Collections.unmodifiableMap(state.instanceCallbacks);
             JavaClass.this. = Collections.unmodifiableList(state.constantFields);
         }
     }
 
     private static class InitializerState {
         public final Map<StringAssignedNamestaticNames;
         public final Map<StringAssignedNameinstanceNames;
         public final Map<StringNamedInstallerstaticCallbacks = new HashMap<StringNamedInstaller>();
         public final Map<StringNamedInstallerinstanceCallbacks = new HashMap<StringNamedInstaller>();
         public final List<ConstantFieldconstantFields = new ArrayList<ConstantField>();
 
         public InitializerState(Ruby runtimeClass superclass) {
             if (superclass == null) {
                  = new HashMap<StringAssignedName>();
                  = new HashMap<StringAssignedName>();
             } else {
                 JavaClass superJavaClass = get(runtime,superclass);
                  = new HashMap<StringAssignedName>(superJavaClass.getStaticAssignedNames());
                  = new HashMap<StringAssignedName>(superJavaClass.getInstanceAssignedNames());
             }
             .putAll();
             .putAll();
         }
     }
 
     private static final Initializer DUMMY_INITIALIZER = new Initializer() {
         public synchronized void initialize() {
             // anything useful we could do here?
         }
     };
     
     public void setupProxy(final RubyClass proxy) {
         assert .isHeldByCurrentThread();
         
         .initialize();
 
         proxy.defineFastMethod("__jsend!");
         final Class<?> javaClass = javaClass();
         if (javaClass.isInterface()) {
             setupInterfaceProxy(proxy);
             return;
         }
 
         proxy.setReifiedClass(javaClass);
         
         assert this. == null;
         this. = proxy;
         if (javaClass.isArray() || javaClass.isPrimitive()) {
             // see note below re: 2-field kludge
             this. = proxy;
             this. = proxy;
             return;
         }
 
         installClassFields(proxy);
         installClassMethods(proxy);
         installClassConstructors(proxy);
         installClassClasses(javaClassproxy);
         
         // flag the class as a Java class proxy.
         proxy.setJavaProxy(true);
         proxy.getSingletonClass().setJavaProxy(true);
 
         // set the Java class name and package
         proxy.setBaseName(javaClass.getSimpleName());
         proxy.setParent(Java.getJavaPackageModule(getRuntime(), javaClass.getPackage()));
         
         // FIXME: bit of a kludge here (non-interface classes assigned to both
         // class and module fields). simplifies proxy extender code, will go away
         // when JI is overhauled (and proxy extenders are deprecated).
         this. = proxy;
         this. = proxy;
 
         applyProxyExtenders();
 
         // TODO: we can probably release our references to the constantFields
         // array and static/instance callback hashes at this point. 
     }
 
     private static void assignAliases(MethodInstaller installerMap<StringAssignedNameassignedNames) {
         String name = installer.name;
         String rubyCasedName = JavaUtil.getRubyCasedName(name);
         addUnassignedAlias(rubyCasedName,assignedNames,installer);
 
         String javaPropertyName = JavaUtil.getJavaPropertyName(name);
         String rubyPropertyName = null;
 
         for (Method methodinstaller.methods) {
             Class<?>[] argTypes = method.getParameterTypes();
             Class<?> resultType = method.getReturnType();
             int argCount = argTypes.length;
 
             // Add scala aliases for apply/update to roughly equivalent Ruby names
             if (rubyCasedName.equals("apply")) {
                 addUnassignedAlias("[]"assignedNamesinstaller);
             }
             if (rubyCasedName.equals("update") && argCount == 2) {
                 addUnassignedAlias("[]="assignedNamesinstaller);
             }
 
             // Scala aliases for $ method names
             if (name.startsWith("$")) {
                 addUnassignedAlias(fixScalaNames(name), assignedNamesinstaller);
             }
 
             // Add property name aliases
             if (javaPropertyName != null) {
                 if (rubyCasedName.startsWith("get_")) {
                     rubyPropertyName = rubyCasedName.substring(4);
                     if (argCount == 0 ||                                // getFoo      => foo
                         argCount == 1 && argTypes[0] == int.class) {    // getFoo(int) => foo(int)
 
                         addUnassignedAlias(javaPropertyName,assignedNames,installer);
                         addUnassignedAlias(rubyPropertyName,assignedNames,installer);
                     }
                 } else if (rubyCasedName.startsWith("set_")) {
                     rubyPropertyName = rubyCasedName.substring(4);
                     if (argCount == 1 && resultType == void.class) {    // setFoo(Foo) => foo=(Foo)
                         addUnassignedAlias(javaPropertyName+'=',assignedNames,installer);
                         addUnassignedAlias(rubyPropertyName+'=',assignedNames,installer);
                     }
                 } else if (rubyCasedName.startsWith("is_")) {
                     rubyPropertyName = rubyCasedName.substring(3);
                     if (resultType == boolean.class) {                  // isFoo() => foo, isFoo(*) => foo(*)
                         addUnassignedAlias(javaPropertyName,assignedNames,installer);
                         addUnassignedAlias(rubyPropertyName,assignedNames,installer);
                     }
                 }
             }
 
             // Additionally add ?-postfixed aliases to any boolean methods and properties.
             if (resultType == boolean.class) {
                 // is_something?, contains_thing?
                 addUnassignedAlias(rubyCasedName+'?',assignedNames,installer);
                 if (rubyPropertyName != null) {
                     // something?
                     addUnassignedAlias(rubyPropertyName+'?',assignedNames,installer);
                 }
             }
         }
     }
     
     private static void addUnassignedAlias(String nameMap<StringAssignedNameassignedNames,
             MethodInstaller installer) {
         if (name == nullreturn;
 
         AssignedName assignedName = assignedNames.get(name);
         // TODO: missing additional logic for dealing with conflicting protected fields.
         if (..moreImportantThan(assignedName)) {
             installer.addAlias(name);
             assignedNames.put(namenew AssignedName(name.));
         } else if (..asImportantAs(assignedName)) {
             installer.addAlias(name);
         }
     }
 
     private void installClassClasses(final Class<?> javaClassfinal RubyModule proxy) {
         // setup constants for public inner classes
         Class<?>[] classes = getDeclaredClasses(javaClass);
 
         for (int i = classes.length; --i >= 0; ) {
             if (javaClass == classes[i].getDeclaringClass()) {
                 Class<?> clazz = classes[i];
 
                 // no non-public inner classes
                 if (!Modifier.isPublic(clazz.getModifiers())) continue;
                 
                 String simpleName = getSimpleName(clazz);
                 if (simpleName.length() == 0) continue;
 
                 final IRubyObject innerProxy = Java.get_proxy_class(,get(getRuntime(),clazz));
 
                 if (IdUtil.isConstant(simpleName)) {
                     if (proxy.getConstantAt(simpleName) == null) {
                         proxy.const_set(getRuntime().newString(simpleName), innerProxy);
                     }
                 } else {
                     // lower-case name
                     if (!proxy.respondsTo(simpleName)) {
                         // define a class method
                         proxy.getSingletonClass().addMethod(simpleNamenew JavaMethodZero(proxy.getSingletonClass(), .) {
                             @Override
                             public IRubyObject call(ThreadContext contextIRubyObject selfRubyModule clazzString name) {
                                 return innerProxy;
                             }
                         });
                     }
                 }
             }
         }
     }
 
     private synchronized void installClassConstructors(final RubyClass proxy) {
         if ( != null) {
             .install(proxy);
              = null;
         }
     }
 
     private synchronized void installClassFields(final RubyClass proxy) {
         assert  != null;
         for (ConstantField field : ) {
             field.install(proxy);
         }
          = null;
     }
 
     private synchronized void installClassMethods(final RubyClass proxy) {
         assert  != null;
         for (NamedInstaller installer : .values()) {
             installer.install(proxy);
         }
          = null;
 
         assert  != null;
         for (NamedInstaller installer : .values()) {
             installer.install(proxy);
         }
          = null;
     }
 
     private void setupClassConstructors(Class<?> javaClass) {
         // TODO: protected methods.  this is going to require a rework
         // of some of the mechanism.
         Constructor[] clsConstructors = getConstructors(javaClass);
         
         // create constructorInstaller; if there are no constructors, it will disable construction
          = new ConstructorInvokerInstaller("__jcreate!");
 
         for (int i = clsConstructors.length; --i >= 0;) {
             // we need to collect all methods, though we'll only
             // install the ones that are named in this class
             Constructor ctor = clsConstructors[i];
             .addConstructor(ctorjavaClass);
         }
     }
     
     private void addField(Map <StringNamedInstallercallbacksMap<StringAssignedNamenames,
             Field fieldboolean isFinalboolean isStatic) {
         String name = field.getName();
 
         if (..lessImportantThan(names.get(name))) return;
 
         names.put(namenew AssignedName(name.));
         callbacks.put(nameisStatic ? new StaticFieldGetterInstaller(namefield) :
             new InstanceFieldGetterInstaller(namefield));
 
         if (!isFinal) {
             String setName = name + '=';
             callbacks.put(setNameisStatic ? new StaticFieldSetterInstaller(setNamefield) :
                 new InstanceFieldSetterInstaller(setNamefield));
         }
     }
     
     private void setupClassFields(Class<?> javaClassInitializerState state) {
         Field[] fields = getFields(javaClass);
         
         for (int i = fields.length; --i >= 0;) {
             Field field = fields[i];
             if (javaClass != field.getDeclaringClass()) continue;
 
             if (ConstantField.isConstant(field)) {
                 state.constantFields.add(new ConstantField(field));
                 continue;
             }
 
             int modifiers = field.getModifiers();
             if (Modifier.isStatic(modifiers)) {
                 addField(state.staticCallbacksstate.staticNamesfield, Modifier.isFinal(modifiers), true);
             } else {
                 addField(state.instanceCallbacksstate.instanceNamesfield, Modifier.isFinal(modifiers), false);
             }
         }
     }
 
     private static String fixScalaNames(String name) {
         String s = name;
         for (Map.Entry<StringStringentry : .entrySet()) {
             s = s.replaceAll(entry.getKey(), entry.getValue());
         }
 
         return s;
     }
 
     private static final Map<StringStringSCALA_OPERATORS;
     static {
         Map<StringStringtmp = new HashMap();
         tmp.put("\\$plus""+");
         tmp.put("\\$minus""-");
         tmp.put("\\$colon"":");
         tmp.put("\\$div""/");
         tmp.put("\\$eq""=");
         tmp.put("\\$less""<");
         tmp.put("\\$greater"">");
         tmp.put("\\$bslash""\\\\");
         tmp.put("\\$hash""#");
         tmp.put("\\$times""*");
         tmp.put("\\$bang""!");
         tmp.put("\\$at""@");
         tmp.put("\\$percent""%");
         tmp.put("\\$up""^");
         tmp.put("\\$amp""&");
         tmp.put("\\$tilde""~");
         tmp.put("\\$qmark""?");
         tmp.put("\\$bar""|");
          = Collections.unmodifiableMap(tmp);
     }
 
     private void setupClassMethods(Class<?> javaClassInitializerState state) {
         // TODO: protected methods.  this is going to require a rework of some of the mechanism.
         Method[] methods = getMethods(javaClass);
 
         for (int i = methods.length; --i >= 0;) {
             // we need to collect all methods, though we'll only
             // install the ones that are named in this class
             Method method = methods[i];
             String name = method.getName();
 
             if (Modifier.isStatic(method.getModifiers())) {
                 AssignedName assignedName = state.staticNames.get(name);
 
                 // For JRUBY-4505, restore __method methods for reserved names
                 if (.containsKey(method.getName())) {
                     installStaticMethods(state.staticCallbacksjavaClassmethodname + );
                     continue;
                 }
 
                 if (assignedName == null) {
                     state.staticNames.put(namenew AssignedName(name.));
                 } else {
                     if (..lessImportantThan(assignedName)) continue;
                     if (!..asImportantAs(assignedName)) {
                         state.staticCallbacks.remove(name);
                         state.staticCallbacks.remove(name + '=');
                         state.staticNames.put(namenew AssignedName(name.));
                     }
                 }
                 installStaticMethods(state.staticCallbacksjavaClassmethodname);
            } else {
                AssignedName assignedName = state.instanceNames.get(name);