Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 
 package org.apache.aries.blueprint.utils;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
TODO: javadoc

Version:
$Rev: 1339639 $, $Date: 2012-05-17 11:21:42 -0400 (Thu, 17 May 2012) $
 
 public class ReflectionUtils {
 
     private static Map<Class<?>, PropertyDescriptor[][]> beanInfos = Collections.synchronizedMap(new WeakHashMap<Class<?>, PropertyDescriptor[][]>());
 
     public static boolean hasDefaultConstructor(Class type) {
         if (!Modifier.isPublic(type.getModifiers())) {
             return false;
         }
         if (Modifier.isAbstract(type.getModifiers())) {
             return false;
         }
         Constructor[] constructors = type.getConstructors();
         for (Constructor constructor : constructors) {
             if (Modifier.isPublic(constructor.getModifiers()) &&
                     constructor.getParameterTypes().length == 0) {
                 return true;
             }
         }
         return false;
     }
     
     public static Set<StringgetImplementedInterfaces(Set<StringclassesClass clazz) {
         if (clazz != null && clazz != Object.class) {
             for (Class itf : clazz.getInterfaces()) {
                 if (Modifier.isPublic(itf.getModifiers())) {
                     classes.add(itf.getName());
                 }
                 getImplementedInterfaces(classesitf);
             }
             getImplementedInterfaces(classesclazz.getSuperclass());
         }
         return classes;
     }
 
     public static Set<StringgetSuperClasses(Set<StringclassesClass clazz) {
         if (clazz != null && clazz != Object.class) {
             if (Modifier.isPublic(clazz.getModifiers())) {
                 classes.add(clazz.getName());
             }
             getSuperClasses(classesclazz.getSuperclass());
         }
         return classes;
     }
 
     public static Method getLifecycleMethod(Class clazzString name) {
         if (name != null) {
            try {
                Method method = clazz.getMethod(name);
                if (..equals(method.getReturnType())) {
                    return method;
                }
            } catch (NoSuchMethodException e) {
                // fall thru
            }
        }
        return null;
    }
    
    public static List<MethodfindCompatibleMethods(Class clazzString nameClass[] paramTypes) {
        List<Methodmethods = new ArrayList<Method>();
        for (Method method : clazz.getMethods()) {
            Class[] methodParams = method.getParameterTypes();
            if (name.equals(method.getName()) && ..equals(method.getReturnType()) && methodParams.length == paramTypes.length && !method.isBridge()) {
                boolean assignable = true;
                for (int i = 0; i < paramTypes.length && assignablei++) {
                    assignable &= paramTypes[i] == null || methodParams[i].isAssignableFrom(paramTypes[i]);
                }
                if (assignable) {
                    methods.add(method);
                }
            }
        }
        return methods;
    }
    public static PropertyDescriptor[] getPropertyDescriptors(Class clazzboolean allowFieldInjection) {
        PropertyDescriptor[][] properties = .get(clazz);
        int index = allowFieldInjection ? 0 : 1;
        
        if (properties == null) {
            properties = new PropertyDescriptor[2][];
            .put(clazzproperties);
        }
        
        if (properties[index] == null) {
            Set<StringpropertyNames = new HashSet<String>();
            Map<String,Methodgetters = new HashMap<StringMethod>();
            Map<String,List<Method>> setters = new HashMap<StringList<Method>>();
            Set<StringillegalProperties = new HashSet<String>();
            
            for (Method method : clazz.getMethods()) {
                if (Modifier.isStatic(method.getModifiers()) || method.isBridge()) continue;
                
                String name = method.getName();
                Class<?> argTypes[] = method.getParameterTypes();
                Class<?> resultType = method.getReturnType();
                
                if (name.length() > 3 && name.startsWith("set") && resultType == . && argTypes.length == 1) {
                    name = decapitalize(name.substring(3));
                    if (!!!setters.containsKey(name)) setters.put(namenew ArrayList<Method>());
                    setters.get(name).add(method);
                    propertyNames.add(name);
                } else if (name.length() > 3 && name.startsWith("get") && resultType != . && argTypes.length == 0) {
                    name = decapitalize(name.substring(3));
                    if (getters.containsKey(name)) illegalProperties.add(name);
                    else propertyNames.add(name);
                    
                    getters.put(namemethod);                    
                } else if (name.length() > 2 && name.startsWith("is") && argTypes.length == 0 && resultType == boolean.class) {
                    name = decapitalize(name.substring(2));
                    if (getters.containsKey(name)) illegalProperties.add(name);
                    else propertyNames.add(name);
                    
                    getters.put(namemethod);                    
                }
                
            }
            Map<StringPropertyDescriptorprops = new HashMap<StringPropertyDescriptor>();
            for (String propName : propertyNames) {
                props.put(propName,
                        new MethodPropertyDescriptor(propNamegetters.get(propName), setters.get(propName)));
            }            
            
            if (allowFieldInjection) {
                for (Class cl = clazzcl != null && cl != Object.classcl = cl.getSuperclass()) {
                    for (Field field : cl.getDeclaredFields()) {
                        if (!!!Modifier.isStatic(field.getModifiers())) {
                            String name = decapitalize(field.getName());
                            PropertyDescriptor desc = props.get(name);
                            if (desc == null) {
                                props.put(namenew FieldPropertyDescriptor(namefield));
                            } else if (desc instanceof MethodPropertyDescriptor) {
                                props.put(name,
                                        new JointPropertyDescriptor((MethodPropertyDescriptordesc,
                                                new FieldPropertyDescriptor(namefield)));
                            } else {
                                illegalProperties.add(name);
                            }
                        }
                    }
                }
            }
            
            List<PropertyDescriptorresult = new ArrayList<PropertyDescriptor>();
            for (PropertyDescriptor prop : props.values()) {
                if (!!!illegalProperties.contains(prop.getName())) result.add(prop);
            }
            
            properties[index] = result.toArray(new PropertyDescriptor[result.size()]); 
        }
        return properties[index];
    }
    private static String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                Character.isUpperCase(name.charAt(0))) {
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }
    public static Object invoke(AccessControlContext accfinal Method methodfinal Object instancefinal Object... argsthrows Exception {
        if (acc == null) {
            return method.invoke(instanceargs);
        } else {
            try {
                return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                        return method.invoke(instanceargs);
                    }            
                }, acc);
            } catch (PrivilegedActionException e) {
                throw e.getException();
            }
        }
    }
    
    public static Object newInstance(AccessControlContext accfinal Class clazzthrows Exception {
        if (acc == null) {
            return clazz.newInstance();
        } else {
            try {
                return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                        return clazz.newInstance();
                    }            
                }, acc);
            } catch (PrivilegedActionException e) {
                throw e.getException();
            }
        }
    }
    
    public static Object newInstance(AccessControlContext accfinal Constructor constructorfinal Object... argsthrows Exception {
        if (acc == null) {
            return constructor.newInstance(args);
        } else {
            try {
                return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                        return constructor.newInstance(args);
                    }            
                }, acc);
            } catch (PrivilegedActionException e) {
                throw e.getException();
            }
        }
    }
    
    public static abstract class PropertyDescriptor {
        private final String name;
        
        public PropertyDescriptor(String name) {
            this. = name;
        }
        
        public String getName() {
            return ;
        }
        
        public abstract boolean allowsGet();
        public abstract boolean allowsSet();
        
        protected abstract Object internalGet(ExtendedBlueprintContainer containerObject instancethrows Exception;
        protected abstract void internalSet(ExtendedBlueprintContainer containerObject instanceObject valuethrows Exception;        
        
        public Object get(final Object instancefinal ExtendedBlueprintContainer containerthrows Exception {            
            if (container.getAccessControlContext() == null) {
                return internalGet(containerinstance);
            } else {
                try {
                    return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        public Object run() throws Exception {
                            return internalGet(containerinstance);
                        }            
                    }, container.getAccessControlContext());
                } catch (PrivilegedActionException e) {
                    throw e.getException();
                }
            }
        }
        public void set(final Object instancefinal Object valuefinal ExtendedBlueprintContainer containerthrows Exception {
            if (container.getAccessControlContext() == null) {
                internalSet(containerinstancevalue);
            } else {
                try {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        public Object run() throws Exception {
                            internalSet(containerinstancevalue);
                            return null;
                        }            
                    }, container.getAccessControlContext());
                } catch (PrivilegedActionException e) {
                    throw e.getException();
                }
            }            
        }
        
        protected Object convert(Object objType typethrows Exception {
            return ExecutionContext.Holder.getContext().convert(objnew GenericType(type));
        }
    }
    
    private static class JointPropertyDescriptor extends PropertyDescriptor {
        private final MethodPropertyDescriptor mpd;
        private final FieldPropertyDescriptor fpd;
        
            super(mpd.getName());
            this. = mpd;
            this. = fpd;
        }
        @Override
        public boolean allowsGet() {
            return .allowsGet() || .allowsGet();
        }
        @Override
        public boolean allowsSet() {
            return .allowsSet() || .allowsSet();
        }
        @Override
        protected Object internalGet(ExtendedBlueprintContainer containerObject instancethrows Exception {
            if (.allowsGet()) return .internalGet(containerinstance);
            else if (.allowsGet()) return .internalGet(containerinstance);
            else throw new UnsupportedOperationException();
        }
        @Override
        protected void internalSet(ExtendedBlueprintContainer containerObject instanceObject valuethrows Exception {
            if (.allowsSet()) .internalSet(containerinstancevalue);
            else if (.allowsSet()) .internalSet(containerinstancevalue);
            else throw new UnsupportedOperationException();
        }
    }
    
    private static class FieldPropertyDescriptor extends PropertyDescriptor {
        // instead of holding on to the java.lang.reflect.Field objects we retrieve it every time. The reason is that PropertyDescriptors are 
        // used as values in a WeakHashMap with the class corresponding to the field as the key
        private final String fieldName;
        private final WeakReference<Class<?>> declaringClass;
        
        public FieldPropertyDescriptor(String nameField field) {
            super(name);
            this. = field.getName();
            this. = new WeakReference(field.getDeclaringClass());
        }
        public boolean allowsGet() {
            return true;
        }
        public boolean allowsSet() {
            return true;
        }
        
        private Field getField(ExtendedBlueprintContainer containerthrows ClassNotFoundExceptionNoSuchFieldException {
            if (.get() == nullthrow new ClassNotFoundException("Declaring class was garbage collected");
            
            return .get().getDeclaredField();
        }
        protected Object internalGet(final ExtendedBlueprintContainer containerfinal Object instancethrows Exception {
            if (useContainersPermission(container)) {
                try {
                    return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        public Object run() throws Exception {
                            return doInternalGet(containerinstance);
                        }                        
                    });
                } catch (PrivilegedActionException pae) {
                    Exception e = pae.getException();
                    if (e instanceof IllegalAccessExceptionthrow (IllegalAccessExceptione;
                    else throw (RuntimeExceptione;
                }
            } else {
                return doInternalGet(containerinstance);
            }
        }
        
        private Object doInternalGet(ExtendedBlueprintContainer containerObject instancethrows Exception {
            Field field = getField(container);
            boolean isAccessible = field.isAccessible();
            field.setAccessible(true);
            try {
                return field.get(instance);
            } finally {
                field.setAccessible(isAccessible);
            }
        }
        protected void internalSet(final ExtendedBlueprintContainer containerfinal Object instancefinal Object valuethrows Exception {
            try {
                Boolean wasSet = AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
                    public Boolean run() throws Exception {
                      if (useContainersPermission(container)) {
                        doInternalSet(containerinstancevalue);
                        return .;
                      }
                      return .;
                    }                        
                });
                if(!!!wasSet) {
                  doInternalSet(containerinstancevalue);
                }
            } catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        
        private void doInternalSet(ExtendedBlueprintContainer containerObject instanceObject valuethrows Exception {
            Field field = getField(container);
            final Object convertedValue = convert(valuefield.getGenericType());
            boolean isAccessible = field.isAccessible();
            field.setAccessible(true);
            try {
                field.set(instanceconvertedValue);
            } finally {
                field.setAccessible(isAccessible);
            }
        }
        
        
Determine whether the field access (in particular the call to java.lang.reflect.AccessibleObject.setAccessible(boolean) should be done with the Blueprint extender's permissions, rather than the joint (more restrictive) permissions of the extender plus the Blueprint bundle. We currently only allow this for classes that originate from inside the Blueprint bundle. Otherwise this would open a potential security hole.

Parameters:
container
Returns:
        private boolean useContainersPermission(ExtendedBlueprintContainer containerthrows ClassNotFoundException {
            if (.get() == nullthrow new ClassNotFoundException("Declaring class was garbage collected");
            ClassLoader loader = .get().getClassLoader();
            
            if (loader == nullreturn false;
            
            if (loader instanceof BundleReference) {
                BundleReference ref = (BundleReferenceloader;
                return ref.getBundle().equals(container.getBundleContext().getBundle());                
            }
            
            return false;
        }
    }
    
    private static class MethodDescriptor {
        private final String methodName;
        private final WeakReference<Class<?>> declaringClass;
        private final List<WeakReference<Class<?>>> argClasses;
        
        public MethodDescriptor(Method method) {
             = method.getName();
             = new WeakReference<Class<?>>(method.getDeclaringClass());
            
            List<WeakReference<Class<?>>> accumulator = new ArrayList<WeakReference<Class<?>>>();
            for (Class<?> c : method.getParameterTypes()) {
                accumulator.add(new WeakReference<Class<?>>(c));
            }
             = Collections.unmodifiableList(accumulator);
        }
        
            Class<?>[] argumentClasses = new Class<?>[.size()];
            for (int i=0; i<.size(); i++) {
                argumentClasses[i] = .get(i).get();
                if (argumentClasses[i] == nullthrow new ClassNotFoundException("Argument class was garbage collected");
            }
            
            if (.get() == nullthrow new ClassNotFoundException("Declaring class was garbage collected");
            
            return .get().getMethod(argumentClasses);
        }
        
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append(.get()).append(".").append().append("(");
            
            boolean first = true;
            for (WeakReference<Class<?>> wcl : ) {
                if (!!!firstbuilder.append(",");
                else first = false;
                
                builder.append(wcl.get());
            }
            
            return builder.toString();
        }
    }
    
    private static class MethodPropertyDescriptor extends PropertyDescriptor {
        // instead of holding on to the java.lang.reflect.Method objects we retrieve it every time. The reason is that PropertyDescriptors are 
        // used as values in a WeakHashMap with the class corresponding to the methods as the key
        private final MethodDescriptor getter;
        private final Collection<MethodDescriptorsetters;
        private MethodPropertyDescriptor(String nameMethod getterCollection<Methodsetters) {
            super(name);
            this. = (getter != null) ? new MethodDescriptor(getter) : null;
            
            if (setters != null) {
                Collection<MethodDescriptoraccumulator = new ArrayList<MethodDescriptor>();
                for (Method s : settersaccumulator.add(new MethodDescriptor(s));
                this. = Collections.unmodifiableCollection(accumulator);
            } else {
                this. = Collections.emptyList();
            }
        }
        
        public boolean allowsGet() {
            return  != null;
        }
        
        public boolean allowsSet() {
            return !!!.isEmpty();
        }
        
        protected Object internalGet(ExtendedBlueprintContainer containerObject instance
                throws Exception {
            if ( != null) {
                return .getMethod(container).invoke(instance);
            } else {
                throw new UnsupportedOperationException();
            }
        }
        
        protected void internalSet(ExtendedBlueprintContainer containerObject instanceObject valuethrows Exception {
            
            Method setterMethod = findSetter(containervalue);
            if (setterMethod != null) {
                setterMethod.invoke(instanceconvert(valuesetterMethod.getGenericParameterTypes()[0]));
            } else {
                throw new ComponentDefinitionException(
                        "No converter available to convert value "+value+" into a form applicable for the " + 
                        "setters of property "+getName());
            }
        }
        
        private Method findSetter(ExtendedBlueprintContainer containerObject valuethrows Exception {
            Class<?> valueType = (value == null) ? null : value.getClass();
            
            Method getterMethod = ( != null) ? .getMethod(container) : null;
            Collection<MethodsetterMethods = getSetters(container);
            
            Method result = findMethodByClass(getterMethodsetterMethodsvalueType);
            
            if (result == nullresult = findMethodWithConversion(setterMethodsvalue);
                        
            return result;
        }
        
        private Collection<MethodgetSetters(ExtendedBlueprintContainer containerthrows Exception {
            Collection<Methodresult = new ArrayList<Method>();
            for (MethodDescriptor md : result.add(md.getMethod(container));
            
            return result;
        }
        
        private Method findMethodByClass(Method getterMethodCollection<MethodsetterMethodsClass<?> arg)
                throws ComponentDefinitionException {
            Method result = null;
            if (!hasSameTypeSetter(getterMethodsetterMethods)) {
                throw new ComponentDefinitionException(
                        "At least one Setter method has to match the type of the Getter method for property "
                                + getName());
            }
            if (setterMethods.size() == 1) {
                return setterMethods.iterator().next();
            }
            
            for (Method m : setterMethods) {
                Class<?> paramType = m.getParameterTypes()[0];
                if ((arg == null && Object.class.isAssignableFrom(paramType))
                        || (arg != null && paramType.isAssignableFrom(arg))) {
                    // pick the method that has the more specific parameter if
                    // any
                    if (result != null) {
                        Class<?> oldParamType = result.getParameterTypes()[0];
                        if (paramType.isAssignableFrom(oldParamType)) {
                            // do nothing, result is correct
                        } else if (oldParamType.isAssignableFrom(paramType)) {
                            result = m;
                        } else {
                            throw new ComponentDefinitionException(
                                    "Ambiguous setter method for property "
                                            + getName()
                                            + ". More than one method matches the  parameter type "
                                            + arg);
                        }
                    } else {
                        result = m;
                    }
                }
            }
            return result;
        }
        
        // ensure there is a setter that matches the type of the getter
        private boolean hasSameTypeSetter(Method getterMethodCollection<MethodsetterMethods) {
            if (getterMethod == null) {
                return true;
            }
            Iterator<Methodit = setterMethods.iterator();
            while (it.hasNext()) {
                Method m = it.next();
                if (m.getParameterTypes()[0].equals(getterMethod.getReturnType())) {
                    return true;
                }
            }
            return false;
        }
        private Method findMethodWithConversion(Collection<MethodsetterMethodsObject valuethrows Exception {
            ExecutionContext ctx = ExecutionContext.Holder.getContext();
            List<MethodmatchingMethods = new ArrayList<Method>();
            for (Method m : setterMethods) {
                Type paramType = m.getGenericParameterTypes()[0];
                if (ctx.canConvert(valuenew GenericType(paramType))) matchingMethods.add(m);
            }
            
            if (matchingMethods.isEmpty()) return null;
            else if (matchingMethods.size() == 1) return matchingMethods.get(0);
            else throw new ComponentDefinitionException(
                    "Ambiguous setter method for property "getName() + 
                    ". More than one method matches the parameter "+value+" after applying conversion.");
        }
        
        public String toString() {
            return "PropertyDescriptor <name: "+getName()+", getter: "++", setter: "+;
        }
    }
    public static Throwable getRealCause(Throwable t) {
        if (t instanceof InvocationTargetException && t.getCause() != null) {
            return t.getCause();
        }
        return t;
    }
New to GrepCode? Check out our FAQ X