001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.util;
018    
019    import java.lang.reflect.Field;
020    import java.lang.reflect.Method;
021    import java.lang.reflect.Modifier;
022    
023    /**
024     * Helper for working with reflection on classes.
025     * <p/>
026     * This code is based on org.apache.camel.spring.util.ReflectionUtils class.
027     */
028    public final class ReflectionHelper {
029    
030        private ReflectionHelper() {
031            // utility class
032        }
033    
034        /**
035         * Callback interface invoked on each field in the hierarchy.
036         */
037        public interface FieldCallback {
038    
039            /**
040             * Perform an operation using the given field.
041             *
042             * @param field the field to operate on
043             */
044            void doWith(Field field) throws IllegalArgumentException, IllegalAccessException;
045        }
046    
047        /**
048         * Action to take on each method.
049         */
050        public interface MethodCallback {
051    
052            /**
053             * Perform an operation using the given method.
054             *
055             * @param method the method to operate on
056             */
057            void doWith(Method method) throws IllegalArgumentException, IllegalAccessException;
058        }
059    
060        /**
061         * Invoke the given callback on all fields in the target class, going up the
062         * class hierarchy to get all declared fields.
063         * @param clazz the target class to analyze
064         * @param fc the callback to invoke for each field
065         */
066        public static void doWithFields(Class<?> clazz, FieldCallback fc) throws IllegalArgumentException {
067            // Keep backing up the inheritance hierarchy.
068            Class<?> targetClass = clazz;
069            do {
070                Field[] fields = targetClass.getDeclaredFields();
071                for (Field field : fields) {
072                    try {
073                        fc.doWith(field);
074                    } catch (IllegalAccessException ex) {
075                        throw new IllegalStateException("Shouldn't be illegal to access field '" + field.getName() + "': " + ex);
076                    }
077                }
078                targetClass = targetClass.getSuperclass();
079            }
080            while (targetClass != null && targetClass != Object.class);
081        }
082    
083        /**
084         * Perform the given callback operation on all matching methods of the given
085         * class and superclasses (or given interface and super-interfaces).
086         *
087         * @param clazz class to start looking at
088         * @param mc the callback to invoke for each method
089         */
090        public static void doWithMethods(Class<?> clazz, MethodCallback mc) throws IllegalArgumentException {
091            // Keep backing up the inheritance hierarchy.
092            Method[] methods = clazz.getDeclaredMethods();
093            for (Method method : methods) {
094                try {
095                    mc.doWith(method);
096                } catch (IllegalAccessException ex) {
097                    throw new IllegalStateException("Shouldn't be illegal to access method '" + method.getName() + "': " + ex);
098                }
099            }
100            if (clazz.getSuperclass() != null) {
101                doWithMethods(clazz.getSuperclass(), mc);
102            } else if (clazz.isInterface()) {
103                for (Class<?> superIfc : clazz.getInterfaces()) {
104                    doWithMethods(superIfc, mc);
105                }
106            }
107        }
108    
109        public static void setField(Field f, Object instance, Object value) {
110            try {
111                boolean oldAccessible = f.isAccessible();
112                boolean shouldSetAccessible = !Modifier.isPublic(f.getModifiers()) && !oldAccessible;
113                if (shouldSetAccessible) {
114                    f.setAccessible(true);
115                }
116                f.set(instance, value);
117                if (shouldSetAccessible) {
118                    f.setAccessible(oldAccessible);
119                }
120            } catch (Exception ex) {
121                throw new UnsupportedOperationException("Cannot inject value of class: " + value.getClass() + " into: " + f);
122            }
123        }
124    
125    }