DynamicAnnotationBuilder.java

  1. package com.gh.mygreen.xlsmapper.xml;

  2. import java.lang.annotation.Annotation;
  3. import java.lang.reflect.InvocationHandler;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Proxy;
  6. import java.util.HashMap;
  7. import java.util.Map;

  8. import com.gh.mygreen.xlsmapper.xml.bind.AnnotationInfo;

  9. import ognl.DefaultTypeConverter;
  10. import ognl.Ognl;
  11. import ognl.OgnlContext;
  12. import ognl.OgnlException;


  13. /**
  14.  * Javassitを利用して、{@link Annotation}のインスタンスを動的に作成するクラス。
  15.  * <p>独自のClassLoaderを設定することが可能。
  16.  * <p>このクラスはシングルトンです。
  17.  *
  18.  * @version 0.5
  19.  * @author Naoki Takezoe
  20.  * @author T.TSUCHIE
  21.  *
  22.  */
  23. public class DynamicAnnotationBuilder {
  24.    
  25.     /**
  26.      * シングルトンのインスタンス。
  27.      */
  28.     private static DynamicAnnotationBuilder INSTANCE = new DynamicAnnotationBuilder();
  29.    
  30.     private ClassLoader classLoader;
  31.    
  32.     private OgnlContext ognlContext;
  33.    
  34.     private DynamicAnnotationBuilder() {
  35.         this.ognlContext = new OgnlContext(
  36.                 new MultipleLoaderClassResolver(), new DefaultTypeConverter(), new AllAllowMemberAccess());
  37.        
  38.     }
  39.    
  40.     /**
  41.      * インスタンスを取得する。
  42.      * @return
  43.      */
  44.     public static DynamicAnnotationBuilder getInstance() {
  45.         return INSTANCE;
  46.     }
  47.    
  48.     /**
  49.      * アノテーションが定義された{@link ClassLoader}を設定する。
  50.      * <p>nullの場合、標準のClassLoaderが使用される。
  51.      * @param classLoader
  52.      */
  53.     public static void init(final ClassLoader classLoader) {
  54.         getInstance().classLoader = classLoader;
  55.     }
  56.    
  57.     /**
  58.      * アノテーションが定義されたClassLoaderとJavaBeansを定義したClassLoaderを設定する。
  59.      * @param classLoader アノテーションを見つけるために使用するClassLoader
  60.      * @param propertyLoaders JavaBeansを見つけるために使用するClassLoader
  61.      */
  62.     public static void init(final ClassLoader classLoader, final ClassLoader[] propertyLoaders) {
  63.         getInstance().classLoader = classLoader;
  64.        
  65.         if(propertyLoaders != null && propertyLoaders.length != 0) {
  66.             Map<Integer, ClassLoader> loaderMap = new HashMap<>();
  67.             for(ClassLoader propertyLoader : propertyLoaders) {
  68.                 loaderMap.put(propertyLoader.hashCode(), propertyLoader);
  69.             }
  70.            
  71.             getInstance().ognlContext = new OgnlContext(
  72.                     new AllAllowMemberAccess(), new MultipleLoaderClassResolver(), new DefaultTypeConverter(), loaderMap);
  73.            
  74.         }
  75.     }
  76.    
  77.     /**
  78.      * 指定したアノテーションのクラス情報から、アノテーションのインスタンスを組み立てる。
  79.      * @param annoClass アノテーションのクラス
  80.      * @param info アノテーションの情報
  81.      * @return アノテーションのインスタンス。
  82.      * @throws AnnotationReadException
  83.      */
  84.     public Annotation buildAnnotation(final Class<?> annoClass, final AnnotationInfo info) throws AnnotationReadException {
  85.        
  86.         final Map<String, Object> defaultValues = new HashMap<>();
  87.         for(Method method : annoClass.getMethods()) {
  88.             final Object defaultValue = method.getDefaultValue();
  89.             if(defaultValue != null) {
  90.                 defaultValues.put(method.getName(), defaultValue);
  91.             }
  92.         }
  93.        
  94.         final Map<String, Object> xmlValues = new HashMap<>();
  95.         for(String key : info.getAttributeKeys()) {
  96.             try {
  97.                 Object value = Ognl.getValue(info.getAttribute(key), ognlContext, new Object());
  98.                 xmlValues.put(key, value);
  99.             } catch(OgnlException e) {
  100.                 throw new AnnotationReadException(String.format("fail annotation attribute %s with ognl.", key), e);
  101.             }
  102.         }
  103.        
  104.         ClassLoader loader = classLoader;
  105.         if(loader == null){
  106.             loader = Thread.currentThread().getContextClassLoader();
  107.         }
  108.        
  109.         Object obj = Proxy.newProxyInstance(loader, new Class[]{annoClass},
  110.                 new InvocationHandler() {
  111.                     @Override
  112.                     public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
  113.                         String name = method.getName();
  114.                         if (name.equals("annotationType")) {
  115.                             return annoClass;
  116.                         } else if(xmlValues.containsKey(name)){
  117.                             return xmlValues.get(name);
  118.                         } else {
  119.                             return defaultValues.get(name);
  120.                         }
  121.                     }
  122.         });
  123.        
  124.         return (Annotation) obj;
  125.     }
  126.    
  127. }