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 }