メタデータ

メタデータ(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

DEMO

定義済

@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 継承