/** * Copyright (C) 2006-2017 INRIA and contributors * Spoon - http://spoon.gforge.inria.fr/ * * This software is governed by the CeCILL-C License under French law and * abiding by the rules of distribution of free software. You can use, modify * and/or redistribute the software under the terms of the CeCILL-C license as * circulated by CEA, CNRS and INRIA at http://www.cecill.info. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-C license and that you accept its terms. */ package spoon.support.util; import spoon.reflect.code.CtExpression; import spoon.reflect.code.CtInvocation; import spoon.reflect.code.CtLiteral; import spoon.reflect.declaration.ModifierKind; import spoon.reflect.factory.Factory; import spoon.reflect.reference.CtExecutableReference; import spoon.reflect.reference.CtFieldReference; import spoon.reflect.reference.CtTypeReference; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; /** * This class is a helper for runtime reflection. */ public abstract class RtHelper { private RtHelper() { } /** * Gets all the runtime fields for a given class (including the * superclasses and superinterfaces). */ public static Field[] getAllFields(Class<?> c) { List<Field> fields = new ArrayList<>(); addAllFields(c, fields); Field[] result = new Field[fields.size()]; return fields.toArray(result); } private static void addAllFields(Class<?> c, List<Field> fields) { if (c != null && c != Object.class) { for (Field f : c.getDeclaredFields()) { fields.add(f); } addAllFields(c.getSuperclass(), fields); for (Class<?> iface : c.getInterfaces()) { addAllFields(iface, fields); } } } /** * Gets all the field references for a given class (including the * superclasses'). */ public static Collection<CtFieldReference<?>> getAllFields(Class<?> c, Factory factory) { Collection<CtFieldReference<?>> l = new ArrayList<>(); for (Field f : getAllFields(c)) { l.add(factory.Field().createReference(f)); } return l; } /** * Gets all the runtime methods for a given class or interface (including * the superclasses' or interfaces'). */ public static Method[] getAllMethods(Class<?> c) { List<Method> methods = new ArrayList<>(); if (c.isInterface()) { getAllIMethods(c, methods); } else { while (c != null && c != Object.class) { for (Method m : c.getDeclaredMethods()) { methods.add(m); } // methods.addAll(Arrays.asList(c.getDeclaredMethods())); c = c.getSuperclass(); } } Method[] result = new Method[methods.size()]; return methods.toArray(result); } private static void getAllIMethods(Class<?> c, List<Method> methods) { for (Method m : c.getDeclaredMethods()) { methods.add(m); } for (Class<?> i : c.getInterfaces()) { getAllIMethods(i, methods); } } /** * Actually invokes from a compile-time invocation (by using runtime * reflection). */ @SuppressWarnings("unchecked") public static <T> T invoke(CtInvocation<T> i) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Object target = i.getTarget() == null ? null : ((CtLiteral<?>) i.getTarget()).getValue(); List<Object> args = new ArrayList<>(); for (CtExpression<?> e : i.getArguments()) { args.add(((CtLiteral<?>) e).getValue()); } Class<?> c = i.getExecutable().getDeclaringType().getActualClass(); ArrayList<Class<?>> argTypes = new ArrayList<>(); for (CtTypeReference<?> type : i.getExecutable().getActualTypeArguments()) { argTypes.add(type.getActualClass()); } return (T) c.getMethod(i.getExecutable().getSimpleName(), argTypes.toArray(new Class[argTypes.size()])) .invoke(target, args.toArray()); } /** * Return the set of modifiers defined by the modifiers integer * (java.lang.reflect). */ public static Set<ModifierKind> getModifiers(int mod) { Set<ModifierKind> set = new HashSet<>(); if (Modifier.isAbstract(mod)) { set.add(ModifierKind.ABSTRACT); } if (Modifier.isFinal(mod)) { set.add(ModifierKind.FINAL); } if (Modifier.isNative(mod)) { set.add(ModifierKind.NATIVE); } if (Modifier.isPrivate(mod)) { set.add(ModifierKind.PRIVATE); } if (Modifier.isProtected(mod)) { set.add(ModifierKind.PROTECTED); } if (Modifier.isPublic(mod)) { set.add(ModifierKind.PUBLIC); } if (Modifier.isStatic(mod)) { set.add(ModifierKind.STATIC); } if (Modifier.isStrict(mod)) { set.add(ModifierKind.STRICTFP); } if (Modifier.isSynchronized(mod)) { set.add(ModifierKind.SYNCHRONIZED); } if (Modifier.isTransient(mod)) { set.add(ModifierKind.TRANSIENT); } if (Modifier.isVolatile(mod)) { set.add(ModifierKind.VOLATILE); } return set; } /** * return all executables of this class */ public static Collection<CtExecutableReference<?>> getAllExecutables(Class<?> clazz, Factory factory) { Collection<CtExecutableReference<?>> l = new ArrayList<>(); for (Method m : clazz.getDeclaredMethods()) { l.add(factory.Method().createReference(m)); } for (Constructor<?> c : clazz.getDeclaredConstructors()) { l.add(factory.Constructor().createReference(c)); } return l; } /** * Looks for first public method of clazz (or any super class or super interface), * whose name is equal to methodName and number of parameters is numParams * @param clazz * @param methodName * @param numParams * @return the found method or null */ public static Method getMethod(Class<?> clazz, String methodName, int numParams) { Method[] methods = clazz.getMethods(); for (Method method : methods) { if (method.getName().equals(methodName)) { Class<?>[] params = method.getParameterTypes(); if (params.length == numParams) { return method; } } } return null; } }