メタデータ
メタデータ(metadata)とは、データについてのデータという意味である。
C#
Attribute
定義済
[Conditional("DEBUG")] 条件つけ
[DllImport("user32.dll"] 外部DLLを呼ぶ
[Obsolete] 推奨されない
[Serializable] シリアル化
自作
[AttributeUsage(AttributeTargets.Class)]
public class CodeReviewAttribute : Attribute
{
public CodeReviewAttribute(int reviewer, string date)
{
this.Reviewer = reviewer;
this.Date = date;
}
public int Reviewer { get; private set; }
public string Date { get; private set; }
public string Comment { get;set; }
}
使い方
[CodeReview("Mike", "2012-01-21", Comment="xxx")]
public class MyClass { }
解析
System.Reflection.MemberInfo info = typeof(MyClass);
CodeReviewAttribue att =
Attribute.GetCustomAttribute(info,typeof(CodeReviewAttribue)) as CodeReviewAttribue;
if(att != null)
{
Console.WriteLine("クラス名:", info.Name);
Console.WriteLine("A:{0},B:{1},C:{2}", att.Reviewer, att.Date, att.Comment);
}
★JavaのAnnotation Pattern
@Retention(RetentionPolicy.RUNTIME)
public @interface MaxLength {
int length() default 0;
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Unique {
Class<?> scope() default Unique.class;
}
public class Country {
private String name;
private List<Region> regions = new ArrayList<Region>();
public Country(String name) {
this.name = name;
}
@MaxLength(length = 6)
public String getName() {
return name;
}
public void addRegion(Region region) {
this.regions.add(region);
}
public List<Region> getRegions() {
return regions;
}
}
public class Region {
private String name = null;
private Country country = null;
public Region(String name, Country country) {
this.name = name;
this.country = country;
this.country.addRegion(this);
}
@Unique(scope = Country.class)
public String getName() {
return name;
}
public Country getCountry() {
return country;
}
}
public abstract class Validator {
public void validate(Object obj) throws ValidationException {
Class<? extends Object> cls = obj.getClass();
for(Method method : cls.getMethods()) {
if(method.isAnnotationPresent(getAnnotationType())) {
doValidate(obj, method,
method.getAnnotation(getAnnotationType()));
}
}
}
protected abstract Class<? extends Annotation> getAnnotationType();
protected abstract void doValidate(Object obj, Method method,
Annotation annotation) throws ValidationException;
}
public class MaxLengthValidator extends Validator {
@Override
protected Class<? extends Annotation> getAnnotationType() {
return MaxLength.class;
}
@Override
protected void doValidate(Object obj, Method method, Annotation annotation)
throws ValidationException {
try {
if(method.getName().startsWith("get")) {
MaxLength maxLength = (MaxLength) annotation;
String value = (String) method.invoke(obj, new Object[0]);
if( value != null && (maxLength.length() < value.length()) ) {
String errMsg = method.getName() + ":Too Long";
throw new ValidationException(errMsg);
}
}
} catch (Exception e) {
throw new ValidationException(e.getMessage());
}
}
}
public class UniqueValidator extends Validator {
@Override
protected Class<? extends Annotation> getAnnotationType() {
return Unique.class;
}
@Override
protected void doValidate(Object obj, Method method, Annotation annotation)
throws ValidationException {
Unique unique = (Unique) annotation;
try {
Method scopeMethod =
obj.getClass().getMethod("get" + unique.scope().getSimpleName());
Object scopeObj = scopeMethod.invoke(obj, new Object[0]);
Method collectionMethod = scopeObj.getClass().getMethod("get" + obj.getClass().getSimpleName() + "s");
List<?> collection = (List<?>) collectionMethod.invoke(scopeObj, new Object[0]);
Object returnValue = method.invoke(obj, new Object[0]);
for(Object otherObj : collection) {
Object otherReturnValue = otherObj.getClass().getMethod(method.getName()).invoke(otherObj, new Object[0]);
if(
!otherObj.equals(obj) &&
otherReturnValue.equals(returnValue)
) {
String errMsg = method.getName() + ":Should be unique";
throw new ValidationException(errMsg);
}
}
} catch (Exception e) {
throw new ValidationException(e.getMessage());
}
}
}
テストコード
Country c = new Country("12345678");
Validator v = new MaxLengthValidator();
try {
v.validate(c);
} catch (ValidationException e) {
e.printStackTrace();
}
Country c1 = new Country("123456");
Country c2 = new Country("123456");
Region r1 = new Region("aaa1", c1);
Region r2 = new Region("aaa1", c1);
Validator v = new UniqueValidator();
try {
v.validate(r1);
} catch (ValidationException e) {
e.printStackTrace();
}
Java
Annotation
定義済
@Override オーバーライド
@SuppressWarnings("unchecked") 警告抑制
@Deprecated 非推奨
自作
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Engineer {
int id();
String date() default "2012-01-21";
String name() default "Mike";
}
使い方
@Engineer(
id = 1001,
date = "2012-01-21",
name = "Mike"
)
public static void method() { }
或いは
public class Target {
...
}
解析
for (Method m : Class.forName(クラス対象).getMethods()) {
if (m.isAnnotationPresent(Engineer.class)) {
try {
m.invoke(null);
} catch (Throwable ex) {
}
}
}
public void init(Class<?> cls) throws Exception {
boolean flag = cls.isAnnotationPresent(Engineer.class);
if (flag) {
Engineer engineer = cls.getAnnotation(Engineer.class);
this.id = engineer.id();
...
}
}
@Inheritedの注意点
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface Desc{
enum Color{
White, Grayish, Yellow;
}
Color c() default Color.White;
}
@Desc(c = Color.White)
abstract class Bird{
public abstract Color getColor();
}
class Sparrow extends Bird{
private Color color;
public Sparrow() {
color = Color.Grayish;
}
public Sparrow(Color color) {
this.color = color;
}
@Override
public Color getColor() {
return this.color;
}
}
enum BirdNest{
Sparrow;
public Bird create(){ // Factory pattern
Desc d = Sparrow.class.getAnnotation(Desc.class);
return d == null ? new Sparrow() : new Sparrow(d.c());
}
}
Bird bird = BirdNest.Sparrow.create();
Color color = bird.getColor(); // White
// @Desc(c = Color.White)がコメントアウトされる場合、出力はGrayish)
※単にSparrowを確認すれば、わかりにくいので、継承階層が深い場合に@Inheritedを使わない方がよい
★メタアノテ―ション
@Target 適用対象
TYPE クラス、アノテ―ションを含むインターフェース、enum
FIELD enumを含むフィールド
METHOD
PARAMETR
PACKAGE
LOCAL_VARIABLE
CONSTRUCTOR
ANNOTATION_TYPE
@Retention 保持期間
RUNTIME コンパイラ時にはクラスファイルに記録され、実行時にはVMに保持される
CLASS コンパイラ時にはクラスファイルに記録されるが、実行時にはVMに保持されない
SOURCE コンパイラ時にはクラスファイルに記録されない
@Documented javadocによりドキュメント化
@Inherited 継承