AnnotationInfo.java

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

  2. import java.io.Serializable;
  3. import java.lang.annotation.Annotation;
  4. import java.util.ArrayList;
  5. import java.util.List;

  6. import javax.xml.bind.annotation.XmlAccessType;
  7. import javax.xml.bind.annotation.XmlAccessorType;
  8. import javax.xml.bind.annotation.XmlAttribute;
  9. import javax.xml.bind.annotation.XmlElement;
  10. import javax.xml.bind.annotation.XmlValue;

  11. import com.gh.mygreen.xlsmapper.util.ArgUtils;
  12. import com.gh.mygreen.xlsmapper.util.Utils;
  13. import com.gh.mygreen.xlsmapper.xml.OgnlValueFormatter;


  14. /**
  15.  * XMLのアノテーション情報を保持する。
  16.  *
  17.  * XMLの使用例:
  18.  *
  19.  * <pre class="highlight"><code class="xml">
  20.  * {@literal <!-- 属性 「name」を持ち必須。--> }
  21.  * {@literal <annotation name="net.java.amateras.xlsbeans.annotation.Sheet">}
  22.  *     {@literal <attribute name="name">'Users'</attribute>}
  23.  * {@literal </annotation>}
  24.  * </code></pre>
  25.  *
  26.  * @version 1.4.1
  27.  * @since 0.5
  28.  * @author T.TSUCHIE
  29.  *
  30.  */
  31. public class AnnotationInfo implements Serializable {
  32.    
  33.     /** serialVersionUID */
  34.     private static final long serialVersionUID = 1L;
  35.    
  36.     /**
  37.      * アノテーションのクラス名
  38.      */
  39.     private String className;
  40.    
  41.     private List<AttributeInfo> attributes = new ArrayList<>();
  42.    
  43.     /**
  44.      * ビルダクラスのインスタンスを取得する。
  45.      * @since 1.1
  46.      * @return
  47.      */
  48.     public static Builder builder() {
  49.         return new Builder();
  50.     }
  51.    
  52.     /**
  53.      * ビルダクラスのインスタンスを取得する。
  54.      * @since 1.1
  55.      * @param valueFormatter JavaオブジェクトをOGNL式に変換するためのクラス。
  56.      * @return
  57.      * @throws IllegalArgumentException valueFormatter is null.
  58.      */
  59.     public static Builder builder(final OgnlValueFormatter valueFormatter) {
  60.         ArgUtils.notNull(valueFormatter, "valueFormatter");
  61.         return new Builder(valueFormatter);
  62.     }
  63.    
  64.     public AnnotationInfo() {
  65.        
  66.     }
  67.    
  68.     private AnnotationInfo(final Builder builder) {
  69.         this.className = builder.className;
  70.         setAttributeInfos(builder.attributeInfos);
  71.     }
  72.    
  73.     @Override
  74.     public String toString() {
  75.        
  76.         StringBuilder sb = new StringBuilder();
  77.         sb.append("AnnotationInfo:")
  78.             .append(String.format(" [name=%s]", getClassName()));
  79.        
  80.         for(AttributeInfo entry : attributes) {
  81.             sb.append(String.format(" [(attr)%s=%s]", entry.name, entry.value));
  82.         }
  83.        
  84.         return sb.toString();
  85.        
  86.     }
  87.    
  88.     /**
  89.      * アノテーションのクラス名を取得する。
  90.      * @return FQCN(完全限定クラス名)。
  91.      */
  92.     public String getClassName() {
  93.         return className;
  94.     }
  95.    
  96.     /**
  97.      * アノテーションのクラス名を設定する。
  98.      * @param className FQCN(完全限定クラス名)を指定します。
  99.      * @throws IllegalArgumentException className is empty.
  100.      */
  101.     @XmlAttribute(name="name", required=true)
  102.     public void setClassName(String className) {
  103.         ArgUtils.notEmpty(className, "className");
  104.         this.className = className;
  105.     }
  106.    
  107.     /**
  108.      * アノテーションの属性を追加する。
  109.      * <p>ただし、既に同じ属性名が存在する場合は、それと入れ替えされます。</p>
  110.      * @param name 属性名。必須です。
  111.      * @param value 値。
  112.      *              <a href="http://s2container.seasar.org/2.4/ja/ognl.html" target="_blank">OGNL形式</a>で指定します。
  113.      * @throws IllegalArgumentException name is empty.
  114.      */
  115.     public void addAttribute(final String name, final String value) {
  116.         ArgUtils.notEmpty(name, "name");
  117.         removeAttribute(name);
  118.         this.attributes.add(AttributeInfo.create(name, value));
  119.     }
  120.    
  121.     /**
  122.      * アノテーションの属性名の一覧を取得する。
  123.      * @return 属性名の一覧情報。
  124.      */
  125.     public String[] getAttributeKeys() {
  126.        
  127.         final List<String> list = new ArrayList<>(attributes.size());
  128.         for(AttributeInfo item : attributes) {
  129.             list.add(item.name);
  130.         }
  131.        
  132.         return list.toArray(new String[list.size()]);
  133.     }
  134.    
  135.     /**
  136.      * アノテーションの属性名を指定して、アノテーションの値を取得する。
  137.      * @param name 属性名。
  138.      * @return 存在しない属性名の場合、nullを返します。
  139.      */
  140.     public String getAttribute(final String name) {
  141.         for(AttributeInfo item : attributes) {
  142.             if(item.name.equals(name)) {
  143.                 return item.value;
  144.             }
  145.         }
  146.        
  147.         return null;
  148.     }
  149.    
  150.     /**
  151.      * 指定したアノテーションの属性情報を含むかどうか。
  152.      * @since 1.1
  153.      * @param name アノテーションの属性名。
  154.      * @return true: 指定したアノテーションの属性名が存在する場合。
  155.      */
  156.     public boolean containsAttribute(final String name) {
  157.         return getAttribute(name) != null;
  158.     }
  159.    
  160.     /**
  161.      * 指定したアノテーションの属性情報を削除します。
  162.      * @since 1.4.1
  163.      * @param name アノテーションの属性名。
  164.      * @return true:指定したアノテーション属性名を含み、それが削除できた場合。
  165.      */
  166.     public boolean removeAttribute(final String name) {
  167.        
  168.         AttributeInfo existInfo = null;
  169.         for(AttributeInfo item : attributes) {
  170.             if(item.name.equals(name)) {
  171.                 existInfo = item;
  172.                 break;
  173.             }
  174.            
  175.         }
  176.        
  177.         if(existInfo != null) {
  178.             this.attributes.remove(existInfo);
  179.             return true;
  180.         }
  181.        
  182.         return false;
  183.        
  184.     }
  185.    
  186.     /**
  187.      * アノテーションの属性情報を保持するクラス。
  188.      * <p>JAXBによるXMLのマッピングのために使用する。</p>
  189.      *
  190.      */
  191.     @XmlAccessorType(XmlAccessType.FIELD)
  192.     public static class AttributeInfo implements Serializable {
  193.        
  194.         /** serialVersionUID */
  195.         private static final long serialVersionUID = 5570368711168203217L;
  196.        
  197.         @XmlAttribute(name="name", required=true)
  198.         String name;
  199.        
  200.         @XmlValue
  201.         String value;
  202.        
  203.         public static AttributeInfo create(final String name, final String value) {
  204.            
  205.             AttributeInfo attr = new AttributeInfo();
  206.             attr.name = name;
  207.             attr.value = value;
  208.             return attr;
  209.         }
  210.        
  211.     }
  212.    
  213.     /**
  214.      * JAXB用のアノテーションの属性情報を設定するメソッド。
  215.      * <p>XMLの読み込み時に呼ばれます。
  216.      *  <br>ただし、Java8からはこのメソッドは呼ばれず、{@link #getAttributeInfos()} で取得したインスタンスに対して要素が追加されます。
  217.      * </p>
  218.      * <p>既存の情報はクリアされます。</p>
  219.      * @since 1.1
  220.      * @param attributeInfos アノテーションの属性情報。
  221.      */
  222.     @XmlElement(name="attribute")
  223.     public void setAttributeInfos(final List<AttributeInfo> attributeInfos) {
  224.         if(attributeInfos == this.attributes) {
  225.             // Java7の場合、getterで取得したインスタンスをそのまま設定するため、スキップする。
  226.             return;
  227.         }
  228.        
  229.         this.attributes.clear();
  230.         for(AttributeInfo attr : attributeInfos) {
  231.             addAttribute(attr.name, attr.value);
  232.         }
  233.     }
  234.    
  235.     /**
  236.      * JAXB用のアノテーションの属性情報を取得するメソッド。
  237.      * <p>XMLの書き込み時に呼ばれます。
  238.      *  <br>Java8から読み込み時に呼ばれるようになり、取得したインスタンスに対して、読み込んだ要素が呼ばれます。
  239.      * </p>
  240.      * @since 1.1
  241.      * @return
  242.      */
  243.     public List<AttributeInfo> getAttributeInfos() {
  244.         return attributes;
  245.     }
  246.    
  247.     /**
  248.      * {@link AnnotationInfo}を組み立てるためのクラス。
  249.      *
  250.      */
  251.     public static final class Builder {
  252.        
  253.         private static final OgnlValueFormatter DEFAULT_VALUE_FORMATTER = new OgnlValueFormatter();
  254.        
  255.         private OgnlValueFormatter valueFormatter;
  256.        
  257.         private String className;
  258.        
  259.         private List<AttributeInfo> attributeInfos;
  260.        
  261.         private Builder() {
  262.             this(DEFAULT_VALUE_FORMATTER);
  263.         }
  264.        
  265.         private Builder(final OgnlValueFormatter valueFormatter) {
  266.             this.valueFormatter = valueFormatter;
  267.             this.attributeInfos = new ArrayList<>();
  268.            
  269.         }
  270.        
  271.         /**
  272.          * 組み立てた{@link AnnotationInfo}のインスタンスを取得する。
  273.          * @return
  274.          */
  275.         public AnnotationInfo buildAnnotation() {
  276.             if(Utils.isEmpty(className)) {
  277.                 throw new IllegalStateException("class name is required.");
  278.             }
  279.            
  280.             return new AnnotationInfo(this);
  281.            
  282.         }
  283.        
  284.         /**
  285.          * アノテーションのクラス名を設定する。
  286.          * @param className アノテーションのクラス名。FQCN(完全限定クラス名)を指定します。
  287.          * @return
  288.          * @throws IllegalArgumentException className is empty.
  289.          */
  290.         public Builder name(final String className) {
  291.             ArgUtils.notEmpty(className, "className");
  292.             this.className = className;
  293.             return this;
  294.         }
  295.        
  296.         /**
  297.          * アノテーションのクラス名を設定する。
  298.          * @param clazz アノテーションのクラス。
  299.          * @return
  300.          * @throws IllegalArgumentException clazz is null.
  301.          */
  302.         public Builder name(final Class<? extends Annotation> clazz) {
  303.             ArgUtils.notNull(clazz, "clazz");
  304.             return name(clazz.getName());
  305.         }
  306.        
  307.         /**
  308.          * アノテーションの属性値を設定する。
  309.          * @param attrName 属性名
  310.          * @param attrValue 属性の値。
  311.          *              <a href="http://s2container.seasar.org/2.4/ja/ognl.html" target="_blank">OGNL形式</a>で指定します。
  312.          * @return
  313.          * @throws IllegalArgumentException attrName is empty.
  314.          */
  315.         public Builder attributeWithNative(final String attrName, final String attrValue) {
  316.             ArgUtils.notEmpty(attrName, "attrName");
  317.             this.attributeInfos.add(AttributeInfo.create(attrName, attrValue));
  318.             return this;
  319.         }
  320.        
  321.         /**
  322.          * アノテーションの属性値を設定する。
  323.          * @param attrName 属性名
  324.          * @param attrValue 属性の値。値は自動的にOGNLの書式に変換されて設定されます。
  325.          * @return
  326.          * @throws IllegalArgumentException attrName is empty.
  327.          */
  328.         public Builder attribute(final String attrName, final Object attrValue) {
  329.             ArgUtils.notEmpty(attrName, "attrName");
  330.            
  331.             String ognlValue = valueFormatter.format(attrValue);
  332.             attributeWithNative(attrName, ognlValue);
  333.            
  334.             return this;
  335.         }
  336.        
  337.     }
  338.    
  339. }