/* * Copyright 2016 Function1. All Rights Reserved. * * Licensed 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 tools.gsf.config.inject; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import tools.gsf.config.Factory; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author Tony Field * @since 2016-07-21 */ public final class InjectForRequestInjector implements Injector { private static final Logger LOG = LoggerFactory.getLogger("tools.gsf.config.inject.InjectForRequestInjector"); private final Factory factory; public InjectForRequestInjector(Factory factory) { this.factory = factory; } /** * Inject ICS runtime objects into the object. Objects flagged with the * {@link InjectForRequest} annotation will be populated by this method by * retrieving the value from the {@link Factory#getObject(String, Class)} * method. * * @param dependent the object to inject into */ public void inject(final Object dependent) { if (dependent == null) { throw new IllegalArgumentException("dependent cannot be null."); } Class<?> c = dependent.getClass(); // first to all annotated public setter methods. for (final Method method : c.getMethods()) { if (method.isAnnotationPresent(InjectForRequest.class)) { injectIntoMethod(dependent, factory, method); } } // and then all annotated fields. while (c != Object.class && c != null) { for (final Field field : c.getDeclaredFields()) { if (field.isAnnotationPresent(InjectForRequest.class)) { injectIntoField(dependent, factory, field); } } c = c.getSuperclass(); } } /** * @param object the object to inject into * @param factory the factory that created the objects that need to be * injected. * @param field field to inject into * @throws SecurityException security exception injecting values into field */ private static void injectIntoField(final Object object, final Factory factory, final Field field) throws SecurityException { final InjectForRequest ifr = field.getAnnotation(InjectForRequest.class); String name = ifr.value(); if (StringUtils.isBlank(name)) { name = field.getName(); } final Object injectionValue = factory.getObject(name, field.getType()); if (injectionValue == null) { throw new InjectionException(factory.getClass().getName() + " does not know how to inject '" + field.getType().getName() + "' into the field '" + field.getName() + "' of object " + object.hashCode() + " (" + object.getClass().getName() + ")."); } field.setAccessible(true); // make private fields accessible LOG.debug("Injecting {} into field {} for {}", injectionValue.getClass().getName(), field.getName(), object.getClass().getName()); try { field.set(object, injectionValue); } catch (final IllegalArgumentException e) { throw new InjectionException("IllegalArgumentException injecting " + injectionValue + " into field " + field.getName(), e); } catch (final IllegalAccessException e) { throw new InjectionException("IllegalAccessException injecting " + injectionValue + " into field " + field.getName(), e); } } /** * @param object the object to inject into * @param factory the factory that created the objects that need to be * injected. * @param method the method to inject into * @throws SecurityException security exception when injecting value into field */ private static void injectIntoMethod(final Object object, final Factory factory, final Method method) throws SecurityException { final InjectForRequest ifr = method.getAnnotation(InjectForRequest.class); String name = ifr.value(); if (StringUtils.isBlank(name)) { name = BeanUtils.findPropertyForMethod(method).getName(); } final Class<?> type = method.getParameterTypes()[0]; final Object injectionValue = factory.getObject(name, type); if (injectionValue == null) { throw new InjectionException(factory.getClass().getName() + " does not know how to inject '" + type.getName() + "' into the method '" + method.getName() + "' of object " + object.hashCode() + " (" + object.getClass().getName() + ")."); } // accessible LOG.debug("Injecting {} into field {} for {}", injectionValue.getClass().getName(), method.getName(), object.getClass().getName()); try { method.invoke(object, injectionValue); } catch (final IllegalArgumentException e) { throw new InjectionException("IllegalArgumentException injecting " + injectionValue + " into method " + method.getName(), e); } catch (final IllegalAccessException e) { throw new InjectionException("IllegalAccessException injecting " + injectionValue + " into method " + method.getName(), e); } catch (final InvocationTargetException e) { throw new InjectionException("InvocationTargetException injecting " + injectionValue + " into method " + method.getName(), e); } } }