public MetaClassRegistryImpl(final int loadDefault, final boolean useAccessible) { this.useAccessible = useAccessible; if (loadDefault == LOAD_DEFAULT) { Map<CachedClass, List<MetaMethod>> map = new HashMap<CachedClass, List<MetaMethod>>(); // let's register the default methods registerMethods(null, true, true, map); final Class[] additionals = DefaultGroovyMethods.additionals; for (int i = 0; i != additionals.length; ++i) { createMetaMethodFromClass(map, additionals[i]); } Class[] pluginDGMs = VMPluginFactory.getPlugin().getPluginDefaultGroovyMethods(); for (Class plugin : pluginDGMs) { registerMethods(plugin, false, true, map); } registerMethods(DefaultGroovyStaticMethods.class, false, false, map); Class[] staticPluginDGMs = VMPluginFactory.getPlugin().getPluginStaticGroovyMethods(); for (Class plugin : staticPluginDGMs) { registerMethods(plugin, false, false, map); } for (Map.Entry<CachedClass, List<MetaMethod>> e : map.entrySet()) { CachedClass cls = e.getKey(); cls.setNewMopMethods(e.getValue()); } } installMetaClassCreationHandle(); final MetaClass emcMetaClass = metaClassCreationHandle.create(ExpandoMetaClass.class, this); emcMetaClass.initialize(); ClassInfo.getClassInfo(ExpandoMetaClass.class).setStrongMetaClass(emcMetaClass); addMetaClassRegistryChangeEventListener( new MetaClassRegistryChangeEventListener() { public void updateConstantMetaClass(MetaClassRegistryChangeEvent cmcu) { synchronized (metaClassInfo) { metaClassInfo.add(cmcu.getNewMetaClass()); DefaultMetaClassInfo.getNewConstantMetaClassVersioning(); Class c = cmcu.getClassToUpdate(); DefaultMetaClassInfo.setPrimitiveMeta(c, cmcu.getNewMetaClass() == null); Field sdyn; try { sdyn = c.getDeclaredField(Verifier.STATIC_METACLASS_BOOL); sdyn.setBoolean(null, cmcu.getNewMetaClass() != null); } catch (Throwable e) { // DO NOTHING } } } }); }
/** * This method is a default implementation for the invoke method given in InvocationHandler. Any * call to a method with a declaring class that is not Object, excluding toString() and default * methods is redirected to invokeCustom. * * <p>Methods like equals and hashcode are called on the class itself instead of the delegate * because they are considered fundamental methods that should not be overwritten. The toString() * method gets special treatment as it is deemed to be a method that you might wish to override * when called from Groovy. Interface default methods from Java 8 on the other hand are considered * being default implementations you don't normally want to change. So they are called directly * too * * <p>In many scenarios, it is better to overwrite the invokeCustom method where the core Object * related methods are filtered out. * * @param proxy the proxy * @param method the method * @param args the arguments * @return the result of the invocation by method or delegate * @throws Throwable if caused by the delegate or the method * @see #invokeCustom(Object, Method, Object[]) * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { VMPlugin plugin = VMPluginFactory.getPlugin(); if (plugin.getVersion() >= 7 && isDefaultMethod(method)) { Object handle = handleCache.get(method); if (handle == null) { handle = plugin.getInvokeSpecialHandle(method, proxy); handleCache.put(method, handle); } return plugin.invokeHandle(handle, args); } if (!checkMethod(method)) { try { if (method.getDeclaringClass() == GroovyObject.class) { if ("getMetaClass".equals(method.getName())) { return getMetaClass(proxy); } else if ("setMetaClass".equals(method.getName())) { return setMetaClass((MetaClass) args[0]); } } return invokeCustom(proxy, method, args); } catch (GroovyRuntimeException gre) { throw ScriptBytecodeAdapter.unwrap(gre); } } try { return method.invoke(this, args); } catch (InvocationTargetException ite) { throw ite.getTargetException(); } }
/** * The complete class structure will be initialized only when really needed to avoid having too * many objects during compilation */ private void lazyClassInit() { if (lazyInitDone) return; synchronized (lazyInitLock) { if (redirect != null) { throw new GroovyBugError( "lazyClassInit called on a proxy ClassNode, that must not happen." + "A redirect() call is missing somewhere!"); } if (lazyInitDone) return; VMPluginFactory.getPlugin().configureClassNode(compileUnit, this); lazyInitDone = true; } }
{ if (VMPluginFactory.getPlugin().getVersion() >= 7) handleCache = new ConcurrentHashMap(); }