AnnotationInfo.java
package com.gh.mygreen.xlsmapper.xml.bind;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlValue;
import com.gh.mygreen.xlsmapper.util.ArgUtils;
import com.gh.mygreen.xlsmapper.util.Utils;
import com.gh.mygreen.xlsmapper.xml.OgnlValueFormatter;
/**
* XMLのアノテーション情報を保持する。
*
* XMLの使用例:
*
* <pre class="highlight"><code class="xml">
* {@literal <!-- 属性 「name」を持ち必須。--> }
* {@literal <annotation name="net.java.amateras.xlsbeans.annotation.Sheet">}
* {@literal <attribute name="name">'Users'</attribute>}
* {@literal </annotation>}
* </code></pre>
*
* @version 1.4.1
* @since 0.5
* @author T.TSUCHIE
*
*/
public class AnnotationInfo implements Serializable {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
/**
* アノテーションのクラス名
*/
private String className;
private List<AttributeInfo> attributes = new ArrayList<>();
/**
* ビルダクラスのインスタンスを取得する。
* @since 1.1
* @return
*/
public static Builder builder() {
return new Builder();
}
/**
* ビルダクラスのインスタンスを取得する。
* @since 1.1
* @param valueFormatter JavaオブジェクトをOGNL式に変換するためのクラス。
* @return
* @throws IllegalArgumentException valueFormatter is null.
*/
public static Builder builder(final OgnlValueFormatter valueFormatter) {
ArgUtils.notNull(valueFormatter, "valueFormatter");
return new Builder(valueFormatter);
}
public AnnotationInfo() {
}
private AnnotationInfo(final Builder builder) {
this.className = builder.className;
setAttributeInfos(builder.attributeInfos);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("AnnotationInfo:")
.append(String.format(" [name=%s]", getClassName()));
for(AttributeInfo entry : attributes) {
sb.append(String.format(" [(attr)%s=%s]", entry.name, entry.value));
}
return sb.toString();
}
/**
* アノテーションのクラス名を取得する。
* @return FQCN(完全限定クラス名)。
*/
public String getClassName() {
return className;
}
/**
* アノテーションのクラス名を設定する。
* @param className FQCN(完全限定クラス名)を指定します。
* @throws IllegalArgumentException className is empty.
*/
@XmlAttribute(name="name", required=true)
public void setClassName(String className) {
ArgUtils.notEmpty(className, "className");
this.className = className;
}
/**
* アノテーションの属性を追加する。
* <p>ただし、既に同じ属性名が存在する場合は、それと入れ替えされます。</p>
* @param name 属性名。必須です。
* @param value 値。
* <a href="http://s2container.seasar.org/2.4/ja/ognl.html" target="_blank">OGNL形式</a>で指定します。
* @throws IllegalArgumentException name is empty.
*/
public void addAttribute(final String name, final String value) {
ArgUtils.notEmpty(name, "name");
removeAttribute(name);
this.attributes.add(AttributeInfo.create(name, value));
}
/**
* アノテーションの属性名の一覧を取得する。
* @return 属性名の一覧情報。
*/
public String[] getAttributeKeys() {
final List<String> list = new ArrayList<>(attributes.size());
for(AttributeInfo item : attributes) {
list.add(item.name);
}
return list.toArray(new String[list.size()]);
}
/**
* アノテーションの属性名を指定して、アノテーションの値を取得する。
* @param name 属性名。
* @return 存在しない属性名の場合、nullを返します。
*/
public String getAttribute(final String name) {
for(AttributeInfo item : attributes) {
if(item.name.equals(name)) {
return item.value;
}
}
return null;
}
/**
* 指定したアノテーションの属性情報を含むかどうか。
* @since 1.1
* @param name アノテーションの属性名。
* @return true: 指定したアノテーションの属性名が存在する場合。
*/
public boolean containsAttribute(final String name) {
return getAttribute(name) != null;
}
/**
* 指定したアノテーションの属性情報を削除します。
* @since 1.4.1
* @param name アノテーションの属性名。
* @return true:指定したアノテーション属性名を含み、それが削除できた場合。
*/
public boolean removeAttribute(final String name) {
AttributeInfo existInfo = null;
for(AttributeInfo item : attributes) {
if(item.name.equals(name)) {
existInfo = item;
break;
}
}
if(existInfo != null) {
this.attributes.remove(existInfo);
return true;
}
return false;
}
/**
* アノテーションの属性情報を保持するクラス。
* <p>JAXBによるXMLのマッピングのために使用する。</p>
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
public static class AttributeInfo implements Serializable {
/** serialVersionUID */
private static final long serialVersionUID = 5570368711168203217L;
@XmlAttribute(name="name", required=true)
String name;
@XmlValue
String value;
public static AttributeInfo create(final String name, final String value) {
AttributeInfo attr = new AttributeInfo();
attr.name = name;
attr.value = value;
return attr;
}
}
/**
* JAXB用のアノテーションの属性情報を設定するメソッド。
* <p>XMLの読み込み時に呼ばれます。
* <br>ただし、Java8からはこのメソッドは呼ばれず、{@link #getAttributeInfos()} で取得したインスタンスに対して要素が追加されます。
* </p>
* <p>既存の情報はクリアされます。</p>
* @since 1.1
* @param attributeInfos アノテーションの属性情報。
*/
@XmlElement(name="attribute")
public void setAttributeInfos(final List<AttributeInfo> attributeInfos) {
if(attributeInfos == this.attributes) {
// Java7の場合、getterで取得したインスタンスをそのまま設定するため、スキップする。
return;
}
this.attributes.clear();
for(AttributeInfo attr : attributeInfos) {
addAttribute(attr.name, attr.value);
}
}
/**
* JAXB用のアノテーションの属性情報を取得するメソッド。
* <p>XMLの書き込み時に呼ばれます。
* <br>Java8から読み込み時に呼ばれるようになり、取得したインスタンスに対して、読み込んだ要素が呼ばれます。
* </p>
* @since 1.1
* @return
*/
public List<AttributeInfo> getAttributeInfos() {
return attributes;
}
/**
* {@link AnnotationInfo}を組み立てるためのクラス。
*
*/
public static final class Builder {
private static final OgnlValueFormatter DEFAULT_VALUE_FORMATTER = new OgnlValueFormatter();
private OgnlValueFormatter valueFormatter;
private String className;
private List<AttributeInfo> attributeInfos;
private Builder() {
this(DEFAULT_VALUE_FORMATTER);
}
private Builder(final OgnlValueFormatter valueFormatter) {
this.valueFormatter = valueFormatter;
this.attributeInfos = new ArrayList<>();
}
/**
* 組み立てた{@link AnnotationInfo}のインスタンスを取得する。
* @return
*/
public AnnotationInfo buildAnnotation() {
if(Utils.isEmpty(className)) {
throw new IllegalStateException("class name is required.");
}
return new AnnotationInfo(this);
}
/**
* アノテーションのクラス名を設定する。
* @param className アノテーションのクラス名。FQCN(完全限定クラス名)を指定します。
* @return
* @throws IllegalArgumentException className is empty.
*/
public Builder name(final String className) {
ArgUtils.notEmpty(className, "className");
this.className = className;
return this;
}
/**
* アノテーションのクラス名を設定する。
* @param clazz アノテーションのクラス。
* @return
* @throws IllegalArgumentException clazz is null.
*/
public Builder name(final Class<? extends Annotation> clazz) {
ArgUtils.notNull(clazz, "clazz");
return name(clazz.getName());
}
/**
* アノテーションの属性値を設定する。
* @param attrName 属性名
* @param attrValue 属性の値。
* <a href="http://s2container.seasar.org/2.4/ja/ognl.html" target="_blank">OGNL形式</a>で指定します。
* @return
* @throws IllegalArgumentException attrName is empty.
*/
public Builder attributeWithNative(final String attrName, final String attrValue) {
ArgUtils.notEmpty(attrName, "attrName");
this.attributeInfos.add(AttributeInfo.create(attrName, attrValue));
return this;
}
/**
* アノテーションの属性値を設定する。
* @param attrName 属性名
* @param attrValue 属性の値。値は自動的にOGNLの書式に変換されて設定されます。
* @return
* @throws IllegalArgumentException attrName is empty.
*/
public Builder attribute(final String attrName, final Object attrValue) {
ArgUtils.notEmpty(attrName, "attrName");
String ognlValue = valueFormatter.format(attrValue);
attributeWithNative(attrName, ognlValue);
return this;
}
}
}