/*
* Copyright 2011 FatWire Corporation. 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 com.fatwire.gst.foundation.controller.action;
import com.fatwire.gst.foundation.controller.annotation.InjectForRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* Helper to inject dependencies into Object based on annotated fields and
* methods.
*
* @author Dolf Dijkstra
* @since Mar 26, 2011
* @deprecated - class due for rewriting
*/
public final class AnnotationInjector {
private static final Logger LOG = LoggerFactory.getLogger("tools.gsf.legacy.controller.action.AnnotationInjector");
/**
* 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 object the object to inject into
* @param factory the factory that created the objects that need to be
* injected.
*/
public static void inject(final Object object, final Factory factory) {
if (object == null) {
throw new IllegalArgumentException("object cannot be null.");
}
if (factory == null) {
throw new IllegalArgumentException("factory cannot be null.");
}
Class<?> c = object.getClass();
// first to all annotated public setter methods.
for (final Method method : c.getMethods()) {
if (method.isAnnotationPresent(InjectForRequest.class)) {
injectIntoMethod(object, 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(object, factory, field);
}
}
c = c.getSuperclass();
}
}
/**
* Finds the fields in the class or super class that are annotated with the
* <tt>annnotationClass</tt> annotation.
*
* @param object the object to inspect.
* @param annnotationClass the annotation to find.
* @return the array of fields with the annotation, never null.
*/
public static Field[] findFieldsWithAnnotation(final Object object,
final Class<? extends Annotation> annnotationClass) {
if (object == null) {
throw new IllegalArgumentException("object must not be null.");
}
if (annnotationClass == null) {
throw new IllegalArgumentException("clazz must not be null.");
}
final List<Field> x = new ArrayList<>();
Class<?> c = object.getClass();
while (c != Object.class && c != null) {
for (final Field field : c.getDeclaredFields()) {
// LOG.trace("Found field: "+field.getName());
if (field.isAnnotationPresent(annnotationClass)) {
x.add(field);
}
}
c = c.getSuperclass();
}
return x.toArray(new Field[x.size()]);
}
/**
* @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() + "' for an action.");
}
field.setAccessible(true); // make private fields accessible
if (LOG.isDebugEnabled()) {
LOG.debug("Injecting " + injectionValue.getClass().getName() + " into field " + field.getName() + " for "
+ 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 {
// LOG.trace("Found annotated field: "+field.getName());
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 field '" + method.getName() + "' for an action.");
}
// accessible
if (LOG.isDebugEnabled()) {
LOG.debug("Injecting " + injectionValue.getClass().getName() + " into field " + method.getName() + " for "
+ 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);
}
}
}