SSISO Community

시소당

자바 5.0 이후 추가기능들

/////////////////////////////////////////////////////////////////////
//  메타  데이타(MetaData  ->Annotation
//  기능:  자바의  필드,  클래스,  메소드에  주석과  같이  별도의  표기법으로  표기
//            하여  개발도구.  배포도구,  런타임  라이버러리  와  같은  특수한  방법으로ㅓ
//            처리할  수  있도록  하는  장치  ==>  XML에  배포  디스크립트  대체
//            XDoclet  ;  JavaDoc에  EJB와  관련된  다양한  정보를  넣어  인터페이스
//            코드를  자동으로  생성      
/////////////////////////////////////////////////////////////////////
//  Annotation의  표현  방법
//      (1)  Mark  Annotation
//              Serializable  인터페이스가  어떤  메소드도  정의되어  있지  않지만
//              이  인터페이스는  객체직렬화가  가능하다는  의미를  마킹하는  용도로
//              사용되는  것과  유사하게  사용된다.  표시하는  방법은  @TODO    식이다.
//      (2)  Single  Value  Annotation
//      값을  하나  가지고  있는  annotation  이다.  예를  들어  @TODO("XXX")      
//      (3)  Full  Annotation
//      두개  이상의  멤버를  가지고  있는  annotation  이다.@TODO("XXX","YYY")
//////////////////////////////////////////////////////////////////////

Annotations이란  무엇인가  ?

-  JCP의  5.0(JDK1.5)스펙의  일부인  JSR-175은  자바의
"metadata  facility(메타데이터  기능)"을  제안한  것이다.  아마  더  적절한  표현은
metacoding(메타코딩)일  것이다.  Annotation은  자바의  클래스와  메소드,필드(변수)들을
보다  상세하게  기술해주고  설명해주는  코드의  일부분인다.  기존의  주석문과  다른  점은
Annotation은  특별한  인터페이스로  구현되어지며  패키지화되고  컴파일  되며  다른  클래스들처럼
import될  수  있다.

===================
Marker  Annotation
===================
우리가  소스를  읽거나  작성할  때  필요한  모든  정보를  제공해주는
Annotation이  어디에  있는지  알려주는  간단한  form이다.

-  예를  든다면,  OODBMS가  코드를  마킹하기  위해  Annotation을  어떻게  사용할지를  생각해보자.
디자이너가  자신들의  persistence  메커니즘을  자바의  직렬화  기능에서    의존적이지  않게  만들기를
원한다고  하자.  Serializable  인터페이스와  transient  키워드의  사용을  피하고  싶다.
마커들의  두  예제는  그  클래스가  persistent  하다는  것을  가르키며서  다른  하나는  어떤  필드가
transient하다는  것을  마킹할  것이다.

import  oodbms.annotation.Persistable;
import  oodbms.annotation.Transient;
@Persistable  public  class  Foo  {
        private  String  field;
        @Transient  private  String  tmpField;
}

-  이렇게  하면  OODBMS는  트랜잭션의  맥락에서  사용되는  클래스를  persistent  한  것으로
인식할  수  있으며  적절하게  이  클래스를  저장하고  업데이트  할  수  있을  것이다.
또한    @Transient라고  마킹된  임시  필드  값을  무시하므로  클래스의  원래  용도를  충족시켜
줄  수  있을  것이다.

=============
Single  value
=============
-  대부분의  annotation은  파라미터들을  필요로  한다.  그러나  하나만을  필요로  하는
특별한  경우  annotation  스펙은  빠른  방법(shorthand)을  제공한다.  우리가  persistent
클래스의  버젼  번호들을  선언하고  싶은  경우를  생각해보자.  여기  한가지  방법이  있다.

Import  oodbms.annotation.Persistable;
Import  oodbms.annotation.Version;
@Persistable
@Version  ("1.0.0")
public  class  Foo  {  }

-  일반적으로  단일  파라미터  annotation은  다음과  같은  형식을  취한다.
@Annotation(param-value).  이는    @Annotation(value=param-value)  에  대해  보다
더  컴팩트한  표현이다.

===================
Normal  annotations
===================
-  대개의  경우  1개  이상의  보다  더  구조화된  정보를  제공하고  싶을  것이다.  이런  경우
annotations은  하나  혹은  그  이상의  이름-값  쌍을  정의하게  해준다.  값들은  자바의
기본  자료형들  (int값들,  String값들,  double값들,boolean  값들,  등등의)  혹은
다른  annotation들이  될것이다.

-  이는  타입  안정성을  유지하면서  매우  복잡한  구조를  생성하게  할것이다.
이는  전통적인  Doclet  태그들에  대해  새로운  annotation이  갖는  혜택중  하나이다.
버젼  번호를  부여하는  예제를  다시  살펴보자  우리는  그  정보들을  보다  더  구조화  하고
싶을  것이다.

@Persistable
@Version(major=1,  minor=0,  micro=0)
public  class  Foo  {  }

-  컴파일러와  Eclipse  3.1  (in  beta)같은  JDK  1.5를  지원하는  syntax-aware  IDE는
이  새로운  Version  annotation의  적절한  사용을  즉시  인식할것이다.예를  들어  이중  한
필드에  대한  오타를  인식한다는  것이다.


=============
Arrays
=============
-  annotation은  배열구문({}를  이용하여  배열을  표현)을  이용하여  다중  값을  취하는  필드
들을  가질  수  있다.  예를  들어  우리가  Javadoc  의  작성자  필드들을  교체하고자  한다면
다음과  같이  다중  값을  허용할  수  있다.

@Authors({
        @Author("Jane  Doe")
        @Author("John  Doe")
})

-  배열  안에  배열을  집어넣을  수도  있고  배열안의  복합된  annotation을  집어  넣을  수도  있다.
  만약  메타  코드들을  annotation으로  표현할  수  없는  경우  아마  이것으로  많은  일을  하려고
  할  것이다.  이  구문은  매우  강력하다.

==============================
사용자정의  Annotations을  선언하기
==============================
-  annotation은  이름을  가지고  타입이  지정되어  혹은  내장된  열거형으로  또는  필요하다면
인터페이스처럼  코드  없이  struct-like  폼안에  선언되어진다.  annotation은  궁극적으로는
메소드,  필드,  혹은  그들이  annotate할  타입들을  위한  여분의  JVM  바이트코드  attribute로
변환될  순수한  데이터  구조이다.

public  @interface  HelloAnno  {
        enum  Scope  {  LOCAL,  WORLD  }
        String  name();
        Scope  scope();
}

위의  선언에서  annotation은  다른  annotation에의  의해서  참조  되어질  수도  있다.

import  oodbms.annotation.Version;
public  @interface  HelloAnno  {
        enum  Scope  {  LOCAL,  WORLD  }
        String  name();
        Scope  scope();
        Version  version();
}

그리고  기본값도  가질  수  있다.

import  oodbms.annotation.Version;
public  @interface  HelloAnno  {
        enum  Scope  {  LOCAL,  WORLD  }
        String  name()  default  "Foo";
        Scope  scope()  default  Scope.LOCAL;
        Version  version();
}

위의  정의는  다음과  같은  두가지  방법으로  정의  될수  있다
@HelloAnno(version=@Version(major=1,minor=0,micro=0))
기본값을  가지는  장점으로  다음과  같이  명시적인  값을  세팅할수  있다
@HelloAnno(name="Bar",  scope=Scope.WORLD,
        version=@Version(major=1,minor=0,micro=0))

선언  기법을  하나만  더  보자.  단일  값을  가지는  annotation을  위해  컴파일러는
단일  필드는  value라는  이름을  가질  것이라고  가정할  것이다.  다음처럼

public  @interface  HelloAnno  {
        String  value()  default  "world";
}

//  usage:  value는  "world"란  값을  할당  받을  것이다
@HelloAnno("world");

//  이렇게  하는  것도  가능하다.
@HelloAnno(value="world")

//  이것도  같게  동작한다.기본값을  취할것이므로
@HelloAnno


-  Annotation  선언들은  그들만의  Annotation을  가질수  있다.  이것을  메타  코딩의
메타라고  보면  될것이다.  스펙에서는  이것들을  "Meta  Attributes"라고  부른다.
예를  들어  @Target  annotation  은  자바의  어떤  요소가  작성하는  애플리케이션에서
수정될수  있는지를  정의하고  있다.  @Target(ElementType.TYPE)은  자바의  열거형(
enum),클래스,  인터페이스만  수정할  수  있도록  제한하고  있다.
@Target(ElementType.CONSTRUCTOR)은  생성자만  수정할  수  있다.

=============================
  @RetentionPolicy  annotation
=============================
  @RetentionPolicy  annotation  는  컴파일러에게  annotation으로  무엇을  할  수  있는지를
알려준다:  SOURCE는  이것을  제거하며  클래스  파일안에  내장된  CLASS와  RUNTIME은    리플렉션을
통해  이를  가능하게  해준다.
-  위의  예를  든  OODBMS는  JVM에  올라가면  바이트코드를  볼수  있는  매우  영리한  클래스  로더를
가지고  있어서  우리는  리플렉션을  쓸  필요성을  못느낀다.  이  Version  annotation은  다음과
같다.

package  oodbms.annotation;
import  java.lang.annotation.*;
@RetentionPolicy(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public  @interface  Version  {
        int  major();
        int  minor()  default  0;
        int  micro()  default  0;
}

///////////////////////////////////////////////////////
JDK  5.0없이  Annotation  하기
///////////////////////////////////////////////////////

-  만약  여러분이  JDK5.0을  설치하지  않았다면  어떻게    이  기능들을  여러분의  프로그램에
사용할  수  있을  것인가.

XDoclet
-  XDoclet과    XDoclet의  AOP(attribute-oriented  programming)  구현은  다른  책들에서
많이  다루어진  주제이기  때문에  여기서  비교를  목적  이상의  개요설명은  하지  않을  것이다.

-  XDoclet은  코드들을  annotating하기  윈한  Javadoc  태그  기반의  접근이다.
Xdoclet  툴을  위한  플러그인들은  새로운  기능들을  제공한다.  메타데이터  구조는  JDK1.5보다
더  단조롭고하고  덜  객체지향적이다.  만약  당신의  IDE가  Javadoc  태그들은  인식하고  모르는
것들에  대해서  반전해서  표시한다면(IntelliJ처럼)  당신의  IDE에게  새로운  태그들에  대해서
알려줘야  한다.  또한  만약  문자열  대신에  integer값을  넘겨줘야  한다면  XDoclet을  도입하기
전까지는  고생좀  할  것이다.  게다가  이런  문제는  발생하기  전까지는  예측하기도  어렵다는  것이다.
-  반면에  XDoclet은  그것을  어떻게  하면  잘  사용하는가에  대한  지식이  있는  누군가가  있는
프로젝트에  적용되어  왔다.  XDoclet은  자바  언어의  일부가  되기  보다는  오히려
직접  교류한다는(대등한  위치에  있다는)  장점을  가지고  있다:  자바언어와  XDoclet은  서로  독립적
이며  서로  다른  속도로  발전하고  있다.
-    만약  Sun이  XDoclet을  적용하다면  자바코드를  다루는  기존의  라이브러리와  UI  툴은  여전히
그대로  남아있을  수  있다.

===================
Commons  attributes
===================

-  아파치의  자카르타  프로젝트는  Commons  Attributes를  제공한다.(Commons  에는  로깅,
데이터  베이스  풀링,  콜렉션  같은  범용  기능을  제공하는  많은  API가  있다.)
이  패키지는  JDK5.0과  매우  유사한  기능들을  이전  버젼의  JDK를  쓰는  사용자들을  위해  제공
하고  있다.

-  오로지  JDK5.0가  @를  쓰는  대신  @@를  쓴다는  구문의  차이와  언어자체에  포함된게  아니라
Javadoc에  이식되어  있다는  점  밖에는  존재하지  않는다.  Attributes  는  클래스로
구현되어  있으므로  post-processing  타임에  높은  수준의  타입  안정성을  보장  받을  수  있다.

위의  예제에서  Version  은  다음과  같이  바꿀  수  있다.

public  class  Version  {
        private  int  major;
        private  int  minor;
        private  int  micro;
        public  Version()  {  }
        public  int  getMajor()  {
                return  major;
        }
        public  void  setMajor(int  major)  {
                this.major  =  major;
        }
        public  int  getMinor()  {
                return  minor;
        }
        public  void  setMinor(int  minor)  {
                this.minor  =  minor;
        }
        public  int  getMicro()  {
                return  micro;
        }
        public  void  setMicro(int  micro)  {
        this.micro  =  micro;
        }
}

그리고  다음과  같이  사용될  수  있다.
/**
  *  @Persistable
  *  @@Version(major=1,minor=0,micro=0)
  */
public  class  Foo  {  }


-  Commons  Attributes  는  attribute    ANT나  MAVEN에  통합되어  있는  컴파일러를
제공하므로  annotation을  포함한  최종  자바  클래스  화일들을  생성할  수  있다.  또한
클래스로부터  annotation을  읽어낼  수  있는  실시간  인터페이스도  제공한다.

-  Commons  Attributes가  가장  잘  만들어진  대안이며  JDK5.0으로  이동이  수월하다는
것도  큰  장점이다.

//////////////////////////////////////////////////////////////////////
//  실습
//  준비할  사항
/////////////////////////////////////////////////////////////////////////////////////////////////
//---------(1)
package  com.sjw.ejb3.jdk5;
public  @interface  InProgress  {
}
//  Annotation은  실제  내부적으로는  Class로  처리한다.
//  이  @InProgress  annotation은  "현재처리중"  이라는  문맥적인  의미를  소스코드  내에서  표현하고  싶을  경우  사용하고자
//  구현한  것이다.
//  내부에  아무런  변수도  가지고  있지  않기  때문에  이  annotation은  MakerAnnotation에  해당된다.
////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////
//---------(2)
package  com.sjw.ejb3.jdk5;
import  java.lang.annotation.Retention;
import  java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public  @interface  TODO  {
  /**
    *  value는  Annotation의  name이고  String은  value의  자료형을  의미한다.
    *  따라서  속성은  <code>@TODO(value="")</code>으로  표현할  수  있다.
    */
  String  value();
}
//  만약에  값을  가지는  annotation을  만들고  싶다면  위와  같이    String  value()  라고
//  표현  해주면  된다.
//  이것이  의미하는  것은  @TODO  annotation에  지정  가능한  값의  변수명이  value이고
//  자료형은  문자열이라는  의미이다.
//  위  아노테이션의  사용은  @TODO(value  =  "해결할  문제가  몇가지  있음  주의바람!")  과  같이  사용할  수  있다.
//  이것은  Single-Value  annotation  이다.

//-------(3)
package  com.sjw.ejb3.jdk5;

/*
//  이  주석  블록은    내장  Annotation  실습시에는  해제  한다.
import  java.lang.annotation.ElementType;
import  java.lang.annotation.Retention;
import  java.lang.annotation.RetentionPolicy;
import  java.lang.annotation.Target;
@Target(
  {
    ElementType.TYPE,                              //  클래스,  인터페이스,  enum
    ElementType.METHOD,                          //  생성자를  제외한  모든  메소드
    ElementType.CONSTRUCTOR,                //  생성자
    ElementType.ANNOTATION_TYPE          //  메타  annotation
    }
)
@Retention(RetentionPolicy.SOURCE)  //  이  annotation은  소스코드에서만  사용됨
*/

public  @interface  Message  {
  public  enum  Priority  {HIGH,  NORMAL,  LOW}

  //  이  속성은  <code>@Message(priority=Message.Priority.HIGH)</code>  으로  표현할  수  있다.
  Priority  priority()  default  Priority.NORMAL;

  //  이  속성은  <code>@Message(description="")</code>  으로  표현할  수  있다.
  String  description();
}


//-------------(4)
////////////////////////////////////
//  Annotation  의  활용예제(Custom  annotation  구현하기)
////////////////////////////////////
package  com.sjw.ejb3.jdk5;
public  class  Example7  {
  @InProgress
  @TODO("아직  메소드를  구현하지  않았습니다.")
  public  int  add(int  a,  int  b)  {
    return  0;
  }

  @TODO(value  =  "0으로  나눌  수  없으므로  예외  처리를  해야  합니다.")
  public  int  div(int  a,  int  b)  {
    return  a  /  b;
  }

  public  int  sub(int  a,  int  b)  {
    return  a  -  b;
  }
}
///////////////////////////////////////////////////////
package  com.sjw.ejb3.jdk5;
import  java.lang.reflect.Method;
public  class  Example8  {
  public  static  void  main(String[]  args)  {
    Object  obj  =  null;
    try  {
      //  annotation을  검사할  클래스의  인스턴스를  생성함
      obj  =  Class.forName("com.sjw.ejb3.jdk5.Example7").newInstance();
    }  catch  (Exception  e)  {
      e.printStackTrace();
    }

    //  해당  클래스에  작성한  메소드를  가져온다.
    Method[]  methods  =  obj.getClass().getDeclaredMethods();

    for  (Method  m  :  methods)  {  //  JDK  5.0의  향상된  루프를  이용
      TODO  todo  =  m.getAnnotation(TODO.class);  //  현재  메소드에서  TODO  annotation이
      //있는지  확인한다.
      if  (todo  ==  null)  {
        System.out.println("@TODO가  구현되지  않은  메소드  :  "  +  m.getName());
      }  else  {
        System.out.println("@TODO가  구현된  메소드  :  "  +  m.getName());
        System.out.println("      내용  -->  "  +  todo.value());
      }
    }
  }
}

//////////////////  내장  아노테이션  /////////////////////////
//(1)  @Override
////////////////////////////////////////////////////////

package  com.sjw.ejb3.jdk5;
public  class  Example9  {
  public  Example9()  {
  }
  @Override
  public  String  toString()  {
    return  super.toString()  +  "  [메소드  오버라이드  테스트]";
  }
  
  @Override    //  ->  컴파일  오류.  왜냐하면  부모에게  getName()이  정의되어  있지  않다.
  public  String  getName()  {
    return  Example9.class.getName();
  }
  
}
//  @Override  는  슈퍼클래스의  메소드를  오버라이드  한다는  의미를  가지고  있다.
//  그래서  위  소스는  컴파일시에  에러가  발생하게  된다.  즉  getName()이라는  메소드가
//  슈퍼  클래스(Object)에  없기  때문이다.
//  위의  소스에서는  toString()  과  getName()메소드는  반드시  오버라이드  해야  한다는  의미.

//////////////////  내장  아노테이션  /////////////////////////
//(2)  @Deprecated
////////////////////////////////////////////////////////

package  com.sjw.ejb3.jdk5;
public  class  Example10  {
  @Deprecated
  public  void  doSomething()  {
    System.out.println("Example10.doSomething()");
  }

  public  static  void  main(String[]  args)  {
    Example10  client  =  new  Example10();
    client.doSomething();  //  deprecated  메소드  호출
  }
}

//  이  아노테이션은  더이상  사용하지  말아야  하는  메서드를  지정할  때    붙이는  아노테이션이다.
//  이  아노테이션에  해당되는  메소드를  사용하였을  때  컴파일러는  경고  메시지를  보낸다.

//////////////////  내장  아노테이션  /////////////////////////
//(3)  @Target
//        @Retention
////////////////////////////////////////////////////////
//  주의  -  이  소스는  앞에  나온    Message  인터페이스와  같으나  주석부분을  제거  하였다.
/////////////////////////////////////////////////////////
package  com.sjw.ejb3.jdk5;
import  java.lang.annotation.ElementType;
import  java.lang.annotation.Retention;
import  java.lang.annotation.RetentionPolicy;
import  java.lang.annotation.Target;
//  @Target  annotation  은  메타  annotation  이라고도  함.
//  이것은  내가  작성한  아노테이션이  어디에  사용될지를  결정하는  아노테이션이다.
//  이  예는  내가  작성하는  Message  아노테이션을  사용할  수  있는  곳을  아래  주석  처리한
//  곳으로  지정하는  것이다.
@Target(
  {
    ElementType.TYPE,                              //  클래스,  인터페이스,  enum
    ElementType.METHOD,                          //  생성자를  제외한  모든  메소드
    ElementType.CONSTRUCTOR,                //  생성자
    ElementType.ANNOTATION_TYPE          //  메타  annotation
    }
)

//  자바  컴파일러가  이  아노테이션을  어떻게  다룰  것인지를  결정하는  것으로
//  이를  지정하지  않으면  런타임시  또는  수행시  해당  아노테이션을  인식할  수  없게  된다.
//  3가지  속성
//  RetentionPolicy.SOURCE  ~  컴파일러가  컴파일시  삭제하여  클래스  파일에  저장되지  않는다.
//  RetentionPolicy.CLASS  ~  클래스  파일에  저장되지만  자바  가상  머신은  무시한다.
//  RetentionPolicy.RUNTIME  ~  클래스  파일에  저장하고  자바  가상  머신을  읽는다.
//  아래와  같은  표현:  메타아노테이션  표시법
@Retention(RetentionPolicy.SOURCE)  //  이  annotation은  소스코드에서만  사용됨

public  @interface  Message  {
  public  enum  Priority  {HIGH,  NORMAL,  LOW}

  //  이  속성은  <code>@Message(priority=Message.Priority.HIGH)</code>  으로  표현할  수  있다.
  Priority  priority()  default  Priority.NORMAL;

  //  이  속성은  <code>@Message(description="")</code>  으로  표현할  수  있다.
  String  description();
}
/////////////////////////////////////////////
//  앞에서  사용한  아노테이션  인터페이스    TODO  이다.
/////////////////////////////////////////////

package  com.sjw.ejb3.jdk5;
import  java.lang.annotation.Retention;
import  java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public  @interface  TODO  {
  /**
    *  value는  Annotation의  name이고  String은  value의  자료형을  의미한다.
    *  따라서  속성은  <code>@TODO(value="")</code>으로  표현할  수  있다.
    */
  String  value();
}

//  위  소스에서  @Retention(RetentionPolicy.RUNTIME)  부분이  지정되어  있지  않다면,
//  Example8을  실행할  경우    @TODO  아노테이션을  붙인  어떠한  메소드도  인식할  수  없다.
//  즉,  아노테이션  하지  않은  것과  같다.


/////////////////////////////////////////////////////////
//  EJB3.0  과  Annotation
/////////////////////////////////////////////////////////

//  EJB3.0에서는  EJB의  속성을  아노테이션을  활용하여  표시하기  때문에
//  과거의  xml  디스크립터를  대체  한다.
//  그래서  EJB3.0  공부는  아노테이션  공부이다.
//////////////////////////////////////////////////////////

////////////////////
//  printf()  와  Varargs
////////////////////

public  class  SE50_ETC_Test  {
  public  static  void  main(String[]  args){
    SE50_ETC_Test  k  =  new  SE50_ETC_Test();
    k.aMethod("갑진이","정숙이","정희","명복이");
    System.out.printf("%d  %s  %n",365,"일은  일년이다.");
    k.aMethod("영제","희제","태제","백황이","남식이");
  }
  public  void  aMethod(String  ...  names){
    for(String  n:  names){
      System.out.println("안녕:  "  +  n);
    }
  }
}
/////////////////////////////수고  많았습니다.////////////////

819 view

4.0 stars