📄 metaclassimpl.java
字号:
if (answer != null) { return answer; } } if (!CompilerConfiguration.isJsrGroovy()) { // is the property the name of a method - in which case return a // closure List methods = getMethods(property); if (!methods.isEmpty()) { return new MethodClosure(object, property); } } // lets try invoke a static getter method // this case is for protected fields. I wish there was a better way... Exception lastException = null; try { if ( !(object instanceof Class) ) { MetaMethod method = findGetter(object, "get" + MetaClassHelper.capitalize(property)); if (method != null) { return MetaClassHelper.doMethodInvoke(object, method, MetaClassHelper.EMPTY_ARRAY); } } } catch (GroovyRuntimeException e) { lastException = e; } /** todo or are we an extensible groovy class? */ if (genericGetMethod != null) { return null; } else { /** todo these special cases should be special MetaClasses maybe */ if (object instanceof Class) { // lets try a static field return getStaticProperty((Class) object, property); } if (object instanceof Collection) { return DefaultGroovyMethods.getAt((Collection) object, property); } if (object instanceof Object[]) { return DefaultGroovyMethods.getAt(Arrays.asList((Object[]) object), property); } if (object instanceof Object) { try { return getAttribute(object,property); } catch (MissingFieldException mfe) { // do nothing } } MetaMethod addListenerMethod = (MetaMethod) listeners.get(property); if (addListenerMethod != null) { /* @todo one day we could try return the previously registered Closure listener for easy removal */ return null; } if (lastException == null) throw new MissingPropertyException(property, theClass); else throw new MissingPropertyException(property, theClass, lastException); } } /** * Get all the properties defined for this type * @return a list of MetaProperty objects */ public List getProperties() { // simply return the values of the metaproperty map as a List return new ArrayList(propertyMap.values()); } /** * This will build up the property map (Map of MetaProperty objects, keyed on * property name). */ private void setupProperties(PropertyDescriptor[] propertyDescriptors) { MetaProperty mp; Method method; MetaMethod getter = null; MetaMethod setter = null; Class klass; // first get the public fields and create MetaFieldProperty objects klass = theClass; while(klass != null) { final Class clazz = klass; Field[] fields = (Field[]) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return clazz.getDeclaredFields(); } }); for(int i = 0; i < fields.length; i++) { // todo: GROOVY-996 // we're only interested in publics and protected if ((fields[i].getModifiers() & (java.lang.reflect.Modifier.PUBLIC | java.lang.reflect.Modifier.PROTECTED)) == 0) continue; // see if we already got this if(propertyMap.get(fields[i].getName()) != null) continue; //System.out.println("adding field " + fields[i].getName() + // " for class " + klass.getName()); // stick it in there! propertyMap.put(fields[i].getName(), new MetaFieldProperty(fields[i])); } // now get the super class klass = klass.getSuperclass(); } // if this an Array, then add the special read-only "length" property if (theClass.isArray()) { propertyMap.put("length", arrayLengthProperty); } // now iterate over the map of property descriptors and generate // MetaBeanProperty objects for(int i=0; i<propertyDescriptors.length; i++) { PropertyDescriptor pd = propertyDescriptors[i]; // skip if the property type is unknown (this seems to be the case if the // property descriptor is based on a setX() method that has two parameters, // which is not a valid property) if(pd.getPropertyType() == null) continue; // get the getter method method = pd.getReadMethod(); if(method != null) getter = findMethod(method); else getter = null; // get the setter method method = pd.getWriteMethod(); if(method != null) setter = findMethod(method); else setter = null; // now create the MetaProperty object //System.out.println("creating a bean property for class " + // theClass.getName() + ": " + pd.getName()); mp = new MetaBeanProperty(pd.getName(), pd.getPropertyType(), getter, setter); // put it in the list // this will overwrite a possible field property propertyMap.put(pd.getName(), mp); } // now look for any stray getters that may be used to define a property klass = theClass; while(klass != null) { final Class clazz = klass; Method[] methods = (Method[]) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return clazz.getDeclaredMethods(); } }); for (int i = 0; i < methods.length; i++) { // filter out the privates if(Modifier.isPublic(methods[i].getModifiers()) == false) continue; method = methods[i]; String methodName = method.getName(); // is this a getter? if(methodName.startsWith("get") && methodName.length() > 3 && method.getParameterTypes().length == 0) { // get the name of the property String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4); // is this property already accounted for? mp = (MetaProperty) propertyMap.get(propName); if(mp != null) { // we may have already found the setter for this if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getGetter() == null) { // update the getter method to this one ((MetaBeanProperty) mp).setGetter(findMethod(method)); } } else { // we need to create a new property object // type of the property is what the get method returns MetaBeanProperty mbp = new MetaBeanProperty(propName, method.getReturnType(), findMethod(method), null); // add it to the map propertyMap.put(propName, mbp); } } else if(methodName.startsWith("set") && methodName.length() > 3 && method.getParameterTypes().length == 1) { // get the name of the property String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4); // did we already find the getter of this? mp = (MetaProperty) propertyMap.get(propName); if(mp != null) { if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getSetter() == null) { // update the setter method to this one ((MetaBeanProperty) mp).setSetter(findMethod(method)); } } else { // this is a new property to add MetaBeanProperty mbp = new MetaBeanProperty(propName, method.getParameterTypes()[0], null, findMethod(method)); // add it to the map propertyMap.put(propName, mbp); } } } // now get the super class klass = klass.getSuperclass(); } } /** * Sets the property value on an object */ public void setProperty(Object object, String property, Object newValue) { // // Unwrap wrapped values fo now - the new MOP will handle them properly // if (newValue instanceof Wrapper) newValue = ((Wrapper)newValue).unwrap(); MetaProperty mp = (MetaProperty) propertyMap.get(property); if(mp != null) { try { mp.setProperty(object, newValue); return; } catch(ReadOnlyPropertyException e) { // just rethrow it; there's nothing left to do here throw e; } catch (TypeMismatchException e) { // tried to access to mismatched object. throw e; } catch (Exception e) { // if the value is a List see if we can construct the value // from a constructor if (newValue == null) return; if (newValue instanceof List) { List list = (List) newValue; int params = list.size(); Constructor[] constructors = mp.getType().getConstructors(); for (int i = 0; i < constructors.length; i++) { Constructor constructor = constructors[i]; if (constructor.getParameterTypes().length == params) { Object value = MetaClassHelper.doConstructorInvoke(constructor, list.toArray()); mp.setProperty(object, value); return; } } // if value is an array Class parameterType = mp.getType(); if (parameterType.isArray()) { Object objArray = MetaClassHelper.asPrimitiveArray(list, parameterType); mp.setProperty(object, objArray); return; } } // if value is an multidimensional array // jes currently this logic only supports metabeansproperties and // not metafieldproperties. It shouldn't be too hard to support // the latter... if (newValue.getClass().isArray() && mp instanceof MetaBeanProperty) { MetaBeanProperty mbp = (MetaBeanProperty) mp; List list = Arrays.asList((Object[])newValue); MetaMethod setter = mbp.getSetter(); Class parameterType = setter.getParameterTypes()[0]; Class arrayType = parameterType.getComponentType(); Object objArray = Array.newInstance(arrayType, list.size()); for (int i = 0; i < list.size(); i++) { List list2 =Arrays.asList((Object[]) list.get(i)); Object objArray2 = MetaClassHelper.asPrimitiveArray(list2, arrayType); Array.set(objArray, i, objArray2); } MetaClassHelper.doMethodInvoke(object, setter, new Object[]{ objArray }); return; } throw new MissingPropertyException(property, theClass, e); } } RuntimeException runtimeException = null; MetaMethod addListenerMethod = (MetaMethod) listeners.get(property); try { if (addListenerMethod != null && newValue instanceof Closure) { // lets create a dynamic proxy Object proxy = MetaClassHelper.createListenerProxy(addListenerMethod.getParameterTypes()[0], property, (Closure) newValue); MetaClassHelper.doMethodInvoke(object, addListenerMethod, new Object[] { proxy }); return; } if (genericSetMethod == null) { // Make sure there isn't a generic method in the "use" cases List possibleGenericMethods = getMethods("set"); if (possibleGenericMethods != null) { for (Iterator i = possibleGenericMethods.iterator(); i.hasNext(); ) { MetaMethod mmethod = (MetaMethod) i.next(); Class[] paramTypes = mmethod.getParameterTypes(); if (paramTypes.length == 2 && paramTypes[0] == String.class) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -