stringtemplate-spring

Spring integration for StringTemplate
git clone https://code.djc.id.au/git/stringtemplate-spring/

src/main/java/au/id/djc/stringtemplate/AnnotationAttributeRendererGenerator.java (6078B) - raw

      1 package au.id.djc.stringtemplate;
      2 
      3 import java.lang.reflect.InvocationTargetException;
      4 import java.lang.reflect.Method;
      5 import java.util.HashMap;
      6 import java.util.List;
      7 import java.util.Map;
      8 import java.util.Map.Entry;
      9 import java.util.logging.Logger;
     10 
     11 import org.springframework.beans.BeansException;
     12 import org.springframework.context.ApplicationContext;
     13 import org.springframework.context.ConfigurableApplicationContext;
     14 import org.springframework.context.support.ApplicationObjectSupport;
     15 import org.springframework.core.annotation.AnnotationUtils;
     16 import org.springframework.util.LinkedMultiValueMap;
     17 import org.springframework.util.MultiValueMap;
     18 import org.springframework.util.ReflectionUtils;
     19 
     20 /**
     21  * This bean will automatically populate your {@link ApplicationContext} with an
     22  * {@link AttributeRenderer} implementation for each method on any (singleton)
     23  * beans which is annotated with {@link AttributeRendererMethod}.
     24  */
     25 public class AnnotationAttributeRendererGenerator extends ApplicationObjectSupport {
     26     
     27     private static final Logger LOG = Logger.getLogger(AnnotationAttributeRendererGenerator.class.getName());
     28     
     29     private static final class MethodWrapper {
     30         
     31         private final String format;
     32         private final String beanName;
     33         private final Method method;
     34         
     35         public MethodWrapper(String format, String beanName, Method method) {
     36             this.format = format;
     37             this.beanName = beanName;
     38             this.method = method;
     39         }
     40         
     41         @Override
     42         public String toString() {
     43             return "MethodWrapper[" + beanName + "," + method.getName() + "]";
     44         }
     45         
     46     }
     47     
     48     private static final class MethodWrappingAttributeRenderer implements AttributeRenderer {
     49         
     50         private final ApplicationContext applicationContext;
     51         private final Class<?> targetClass;
     52         private final Map<String, MethodWrapper> methodsByFormat = new HashMap<String, MethodWrapper>();
     53         
     54         public MethodWrappingAttributeRenderer(ApplicationContext applicationContext,
     55                 Class<?> targetClass, List<MethodWrapper> methodWrappers) {
     56             this.applicationContext = applicationContext;
     57             this.targetClass = targetClass;
     58             for (MethodWrapper methodWrapper : methodWrappers) {
     59                 methodsByFormat.put(methodWrapper.format, methodWrapper);
     60             }
     61             LOG.info("Registering generated AttributeRenderer targeting " + targetClass.getName() + " with methods " + methodsByFormat);
     62         }
     63         
     64         @Override
     65         public Class<?> getTargetClass() {
     66             return targetClass;
     67         }
     68         
     69         @Override
     70         public String toString(Object o) {
     71             return toString(o, "");
     72         }
     73         
     74         @Override
     75         public String toString(Object o, String formatName) {
     76             MethodWrapper methodWrapper = methodsByFormat.get(formatName);
     77             if (methodWrapper == null) {
     78                 if (!formatName.isEmpty()) {
     79                     return toString(o, "");
     80                 } else {
     81                     return o.toString();
     82                 }
     83             }
     84             Object bean = applicationContext.getBean(methodWrapper.beanName);
     85             try {
     86                 return (String) methodWrapper.method.invoke(bean, o);
     87             } catch (IllegalArgumentException e) {
     88                 throw new RuntimeException(e);
     89             } catch (IllegalAccessException e) {
     90                 throw new RuntimeException(e);
     91             } catch (InvocationTargetException e) {
     92                 throw new RuntimeException(e);
     93             }
     94         }
     95         
     96     }
     97     
     98     private final MultiValueMap<Class<?>, MethodWrapper> methodsByTargetClass = new LinkedMultiValueMap<Class<?>, MethodWrapper>();
     99     
    100     @Override
    101     protected void initApplicationContext() throws BeansException {
    102         String[] beanNames = getApplicationContext().getBeanNamesForType(Object.class, false, true);
    103         for (final String beanName : beanNames) {
    104             Object bean = getApplicationContext().getBean(beanName);
    105             ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
    106                 @Override
    107                 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
    108                     AttributeRendererMethod annotation = AnnotationUtils.findAnnotation(method, AttributeRendererMethod.class);
    109                     if (annotation != null) {
    110                         if (method.getParameterTypes().length != 1) {
    111                             throw new IllegalArgumentException("AttributeRenderer method does not take exactly one argument: "
    112                                     + method.getName() + " of bean " + beanName);
    113                         }
    114                         if (!String.class.isAssignableFrom(method.getReturnType())) {
    115                             throw new IllegalArgumentException("AttributeRenderer method does not return String: "
    116                                     + method.getName() + " of bean " + beanName);
    117                         }
    118                         methodsByTargetClass.add(method.getParameterTypes()[0],
    119                                 new MethodWrapper(annotation.format(), beanName, method));
    120                     }
    121                 }
    122             });
    123         }
    124         registerAttributeRendererBeans();
    125     }
    126     
    127     private void registerAttributeRendererBeans() {
    128         int i = 1;
    129         for (Entry<Class<?>, List<MethodWrapper>> entry : methodsByTargetClass.entrySet()) {
    130             MethodWrappingAttributeRenderer attributeRenderer =
    131                 new MethodWrappingAttributeRenderer(getApplicationContext(), entry.getKey(), entry.getValue());
    132             ((ConfigurableApplicationContext) getApplicationContext()).getBeanFactory().registerSingleton(
    133                     String.format("generatedAttributeRenderer#%d-targeting-%s", i, entry.getKey().getName()),
    134                     attributeRenderer);
    135             i ++;
    136         } 
    137     }
    138 
    139 }