/* * 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.nifi.init; import org.apache.nifi.logging.ComponentLog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * This class is a copy of org.apache.nifi.util.ReflectionUtils. Ultimately the * documentation generation component should be moved to a place where it can * depend on this directly instead of copying it in. * * */ public class ReflectionUtils { private final static Logger LOG = LoggerFactory.getLogger(ReflectionUtils.class); /** * Invokes all methods on the given instance that have been annotated with * the given annotation. If the signature of the method that is defined in * <code>instance</code> uses 1 or more parameters, those parameters must be * specified by the <code>args</code> parameter. However, if more arguments * are supplied by the <code>args</code> parameter than needed, the extra * arguments will be ignored. * * @param annotation annotation * @param instance instance * @param logger the ComponentLog to use for logging any errors. If null, * will use own logger, but that will not generate bulletins or easily tie * to the Processor's log messages. * @param args args * @return <code>true</code> if all appropriate methods were invoked and * returned without throwing an Exception, <code>false</code> if one of the * methods threw an Exception or could not be invoked; if <code>false</code> * is returned, an error will have been logged. */ public static boolean quietlyInvokeMethodsWithAnnotation( final Class<? extends Annotation> annotation, final Object instance, final ComponentLog logger, final Object... args) { for (final Method method : instance.getClass().getMethods()) { if (method.isAnnotationPresent(annotation)) { final boolean isAccessible = method.isAccessible(); method.setAccessible(true); try { final Class<?>[] argumentTypes = method.getParameterTypes(); if (argumentTypes.length > args.length) { if (logger == null) { LOG.error("Unable to invoke method {} on {} because method expects {} parameters but only {} were given", new Object[]{method.getName(), instance, argumentTypes.length, args.length}); } else { logger.error("Unable to invoke method {} on {} because method expects {} parameters but only {} were given", new Object[]{method.getName(), instance, argumentTypes.length, args.length}); } return false; } for (int i = 0; i < argumentTypes.length; i++) { final Class<?> argType = argumentTypes[i]; if (!argType.isAssignableFrom(args[i].getClass())) { if (logger == null) { LOG.error("Unable to invoke method {} on {} because method parameter {} is expected to be of type {} but argument passed was of type {}", new Object[]{method.getName(), instance, i, argType, args[i].getClass()}); } else { logger.error("Unable to invoke method {} on {} because method parameter {} is expected to be of type {} but argument passed was of type {}", new Object[]{method.getName(), instance, i, argType, args[i].getClass()}); } return false; } } try { if (argumentTypes.length == args.length) { method.invoke(instance, args); } else { final Object[] argsToPass = new Object[argumentTypes.length]; for (int i = 0; i < argsToPass.length; i++) { argsToPass[i] = args[i]; } method.invoke(instance, argsToPass); } } catch (final InvocationTargetException ite) { if (logger == null) { LOG.error("Unable to invoke method {} on {} due to {}", new Object[]{method.getName(), instance, ite.getCause()}); LOG.error("", ite.getCause()); } else { logger.error("Unable to invoke method {} on {} due to {}", new Object[]{method.getName(), instance, ite.getCause()}); } } catch (final IllegalAccessException | IllegalArgumentException t) { if (logger == null) { LOG.error("Unable to invoke method {} on {} due to {}", new Object[]{method.getName(), instance, t}); LOG.error("", t); } else { logger.error("Unable to invoke method {} on {} due to {}", new Object[]{method.getName(), instance, t}); } return false; } } finally { if (!isAccessible) { method.setAccessible(false); } } } } return true; } }