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 */ 017package org.apache.camel.util; 018 019import java.lang.reflect.Field; 020import java.lang.reflect.Method; 021import 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 */ 028public 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 * <p/> 087 * <b>Important:</b> This method does not take the 088 * {@link java.lang.reflect.Method#isBridge() bridge methods} into account. 089 * 090 * @param clazz class to start looking at 091 * @param mc the callback to invoke for each method 092 */ 093 public static void doWithMethods(Class<?> clazz, MethodCallback mc) throws IllegalArgumentException { 094 // Keep backing up the inheritance hierarchy. 095 Method[] methods = clazz.getDeclaredMethods(); 096 for (Method method : methods) { 097 if (method.isBridge()) { 098 // skip the bridge methods which in Java 8 leads to problems with inheritance 099 // see https://bugs.openjdk.java.net/browse/JDK-6695379 100 continue; 101 } 102 try { 103 mc.doWith(method); 104 } catch (IllegalAccessException ex) { 105 throw new IllegalStateException("Shouldn't be illegal to access method '" + method.getName() + "': " + ex); 106 } 107 } 108 if (clazz.getSuperclass() != null) { 109 doWithMethods(clazz.getSuperclass(), mc); 110 } else if (clazz.isInterface()) { 111 for (Class<?> superIfc : clazz.getInterfaces()) { 112 doWithMethods(superIfc, mc); 113 } 114 } 115 } 116 117 public static void setField(Field f, Object instance, Object value) { 118 try { 119 boolean oldAccessible = f.isAccessible(); 120 boolean shouldSetAccessible = !Modifier.isPublic(f.getModifiers()) && !oldAccessible; 121 if (shouldSetAccessible) { 122 f.setAccessible(true); 123 } 124 f.set(instance, value); 125 if (shouldSetAccessible) { 126 f.setAccessible(oldAccessible); 127 } 128 } catch (Exception ex) { 129 throw new UnsupportedOperationException("Cannot inject value of class: " + value.getClass() + " into: " + f); 130 } 131 } 132 133}