go to http://oracle.in.th

Friday, September 25, 2009

Annotation Part#1

จาก EJB 2.1 ถ้าหากใครลองเขียนหรือใช้งานดูจะพบว่ามันยุ่งยากมาก ขนาดแค่ Bean เดียวกว่าจะ implement ออกมาก็เหนื่อยแล้ว เพราะมีการ config มากทำให้การใช้งาน EJB 2.1 ค่อนข้างจุกจิก วุ่นวายและยุ่งยาก ที่เป็นเช่นนี้เพราะ การออกแบบ ejb2 ของ sun นั้นได้แบ่ง programmer ออกตาม ตามหน้าที่โดยจะแบ่งหน้าที่เป็น 3 ฝ่ายโดยคร่าวๆดังนี้
  • Programmer: programmer เป็นผู้เขียน beans ทั้งหลายโดยที่แต่ละ beans นั้นจะทำหน้าที่เพียงแค่อย่างใดอย่างหนึ่งเท่านั้น
  • Assembler: assembler นั้นจะเป็นผู้ที่รู้เกี่ยวกับ business logic ดีมากๆ เป็นผู้นำ beans ต่างๆเหล่านี้มาร้อยเรียงกันใหม่จนหลายเป็น services
  • Deployer: เป็นผู้ที่นำ beans ต่างๆเอาเข้าระบบ รวมทั้งเป็นผู้ที่คอย config xml ต่างๆทั้งหมด
จะเห็นว่าถ้าหากในองค์กรเรามี role ต่างๆเหล่านี้ ภาระการ config จะตกอยู่กับ deployer ส่วน programmer นั้นไม่จำเป็นต้อง config เองและไม่ต้องรู้ business เพราะ assembler จะเป็นผู้นำไปร้อยเรียงเอง ซึ่งถ้าถามว่าในองค์กรขนาดเล็กจะมีคนที่ทำหน้าที่อย่างที่ sun กำหนดไหม คำตอบคือไม่ ยกตัวอย่างเช่น software house ในไทย programmer คนเดียวทำงานตั้งแต่ programmer ยัน SA หรือจนไปถึง PM, Consultant ออกไปหาลูกค้าด้วยยังมีเลย ดังนั้นการที่เราจะใช้ ejb2.1 นั้นต้องยุ่งยากมาก ทำให้การแบ่งหน้าที่ตามที่ sun เป็นผู้ออกแบบไว้เป็นไปไม่ได้

และเนื่องจากว่า beans ที่ programmer เขียนขึ้นมานั้นจะไม่สามารถนำมาทดสอบได้เพราะว่ายังไม่มีการ config ไม่มีการนำไป deploy ดังนั้นถ้าหาก deployer ไม่ deploy ให้ก็จะไม่มีทาง check ได้ว่า beans ที่ programmer เขียนนั้นถูกไหมดังนั้นมันเป็นเรื่องที่ยุ่งยากมากเพราะต้องคอยประสานกับอีกฝ่ายทำให้ระยะเวลาการทำงานมากขึ้น แต่การที่ programmer จะมา config เองนั้น เป็นเรื่องที่ปวดตับ (เน้นว่าปวดตับไม่ใช่ปวดหัว) มากกับ programmer ดังนั้นจึงมีคนเสนอมาว่าการ config ต่างๆนั้น แทบจะไม่ได้มีการเปลี่ยนแปลงอะไรเลย

ทำไมเราต้องมาแยกกันด้วยทำไมเราไม่เอา config เหล่านั้นลงใน code เลย ซึ่งแนวคิดนี้ได้ถูกนำไปพัฒนาจนกลายเป็น meta data ที่ใส่ลงไปใน program แต่จะไม่ถูกทำงานตอนเวลา compile time แต่จะถูกอ่านค่าต่างๆเหล่านี้เวลา runtime เพื่ออ่านค่า config เหล่านี้ออกมา ซึ่ง metadata ตัวนี้เราเรียกว่า XDocLet โดยเราเขียนค่า config เหล่านี้ลงใน code จากนั้น XDoclet จะสร้าง (generate) xml config ต่างๆให้หรือว่าแม้กระทั้ง java source code โดยพื้นฐานนี้มาจาก JavaDoc ซึ่งเราสั่งเกตไหมว่าเราสามารถ generate JavaDoc มาจาก source code ได้เลย เพียงแต่เราต้องใส่ comment เข้าไปเพื่อไว้เป็นรายละเอียดของ JavaDoc เท่านั้น เช่น

/**
* Returns an Image object that can then be painted on the screen.
* The url argument must specify an absolute {@link URL}. The name
* argument is a specifier that is relative to the url argument.
* <>
* This method always returns immediately, whether or not the
* image exists. When this applet attempts to draw the image on
* the screen, the data will be loaded. The graphics primitives
* that draw the image will incrementally paint on the screen.
*
* @param url an absolute URL giving the base location of the image
* @param name the location of the image, relative to the url argument
* @return the image at the specified URL
* @see Image
*/
public Image getImage(URL url, String name) {
try {
return getImage(new URL(url, name));
} catch (MalformedURLException e) {
return null;
}
}

ใช้ @ ไปเพื่อให้ JavaDoc Tool อ่านไปเพื่อนำเอาไปใช้ทำ API Doc แต่สังเกตว่าต้องมีการใส่ comment ด้วยเพราะว่าเครื่องหมาย @ นั้นยังไม่รองรับใน J2SE 1.4 ซึ่งอาจจะยังงงๆอยู่ลองดูดังรูปด้านล่าง
 

Annotation - JavaDoc to API Doc
ต่อมา sun ได้นำแนวคิดนี้ไปผนวกกับ java ใน version 5.0 ซึ่งทำให้ EJB 3.0 พลอยได้รับอานิสงส์นี้ไปด้วย จากที่ต้อง config xml ที่แสนปวดตับกลายมาเป็นประกาศการ config เหล่านั้นลงใน java code แทน ซึ่ง java จะเรียก meta data นี้ว่า annotation
Annotation นั้นคือ meta data ที่แทรกลงไปใน code แต่จะไม่ถูก compile เหมือนปกติแต่จะเป็นตัวบ่งบอก ตัว java runtime (JRE) ว่า ขณะ ณ ตอนนั้นให้ทำอะไรซึ่งจะแบ่ง annotation เป็น 3 ประเภทคือ

  • Information for the compiler : เป็น annotation ที่บอก compile เพื่อไว้ใช้สำหรับ detect error หรือ suppress warnings ยกตัวอย่างเช่น


    • @Override เพื่อบ่งบอกว่า method นี้ถูก override มาจาก class แม่
    • @Deprecated เพื่อบ่งบอกว่า method หรือ class
    นี้นั้นควรที่จะหลีกเลี่ยงหรือว่าไม่ควรจะใช้เพราะว่าเป็นอันตรายหรือว่ามี method ที่ดีกว่านี้ให้เลือกใช้

  • Compiler-time and deployment-time processing : เป็น annotation ที่ให้ Software tools อ่าน annotation เหล่านั้นเพื่อนำไปสร้าง file ต่างๆ เช่น xml, javadoc และอื่นๆ
  • Runtime processing : เป็น annotation ที่บ่งบอกให้ JRE นั้นทำงานตอน runtime
ซึ่งเราก็จะมาดูวิธีการสร้างและวิธีการเรียกใช้กันโดยที่เราจะเน้นที่ annotation แบบ Runtime processing เพียงเท่านั้นเพราะว่าใน EJB3.0 นั้นไม่มีการ config xml และ annotation ใน EJB3.0 จะทำงานต่างกันกับ XDoclet เพราะว่าไม่ใช่ annotation แบบ Compiler-time and deployment-time processing แต่เป็นแบบ Runtime processing เรามาลองดูกันเลยดีกว่า แต่ไม่ได้หมายความว่าเราจะไม่สามารถสร้าง annotation แบบ Information for the compiler ได้ เราทำได้โดยไปกำหนด policy ตอนที่เราสร้าง annotation ซึ่งลองไปดู code กันเลยดีกว่า ซึ่งเราจะสร้าง annotation ไว้ทดลองสองตัวคือ

// mytag.Author.java
package mytag;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String name();
}

การสร้าง annotation ใช้ @interface ในการประกาศซึ่งในที่นี้เราตั้งชื่อว่า Author จากนั้นเรากำหนด annotation ของเราให้เป็นแบบ Runtime processing โดยกำหนด policy ดังนี้

@Retention(RetentionPolicy.RUNTIME)

ซึ่งการกำหนด policy นั้นมีด้วยกัน 3 อย่างคือ
  • RetentionPolicy.CLASS: Information for the compiler
  • RetentionPolicy.RUNTIME: Runtime processing
  • RetentionPolicy.SOURCE: Compiler-time and deployment-time processing
จากนั้นก็จะมีการ set element ที่ชื่อว่า name ด้วยซึ่งตรงนี้จะมีกี่อันก็ได้และต้องตั้งตาม syntax นี้

<type> <nameofelement>( );

สังเกตุว่าเหมือนการประกาศ abstract method ธรรมดาเพียงแต่ไม่มีการรับ parameter ใดๆทั้งสิ้นใน method นั้น ใน annotation จะมีแต่การประกาศ element เท่านั้นไม่มีการประกาศ attribute หรือ method ใดๆทั้งสิ้น จากนั้นเราก็มาดู annotation อีกตัวคือ

// mytag.Version.java
package mytag;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Version {
  int major();
  int minor();
}

annotation Version จะมี element ด้วยกันสองตัว annotation Author เราเอามาใช้ในการเก็บชื่อว่าใครเป็นคนเขียน class, method หรือ attribute นี้ขึ้นมา ส่วน annotation Version จะบ่งบอกว่า class, method หรือ attribute นั้นผ่านการปรับปรุงมาถึง version ไหนแล้ว การใช้ annotation มีลักษณะเป็นแบบ location sensitive คือ เมื่อเราเอา annotation ไปแปะไว้ตรงหน้าอะไร ก็จะเป็นการประกาศ annotation ของ สิ่ง นั้น เช่น เอาไว้หน้า class มันก็จะเป็น annotation ของ class นั้นๆ เป็นต้น ซึ่งการประกาศ annotation นั้นสามารถประกาศได้ 2 ชนิดคือ
  • Class Annotation
  • Class Member Annotation
ตอนหน้าเราจะมาดูกันว่า Class Annotation  และ Class Member Annotation เป็นอย่างไร

Reference from : dr. Werasak Suengtaworn

Compose by : @plaumkamon
ข้อเขียนนี้ช่วยฉัน:  

7 comments:

Unknown said...

annotation ทำให้หลายอย่างง่ายขึ้นจริงๆ ผมก็มองว่าการใช้ annotation มาถูกทางแล้ว

แล้ว annotation ไม่เิชิงว่าเป็นการทดแทนสิ่งที่มีอยู่ก่อน แต่เป็นการเพิ่มทางเลือกให้กับการพัฒนาแบบเดิมๆ

:D

Rice Cooker said...

@Phamonyut เห็นด้วยอย่างยิ่งครับ อย่าง xml config ที่ว่าจะมาแทน .porperties เอาเข้าจริงบางครั้งผมยังเลือก .properties ในการ config เลย เพราะมันง่ายดี

Kim said...

@plaumkamon, series นี้มีกี่ตอนครับ
จะได้ให้ @sanivipa เตรียมทำ TOC ไว้ก่อนเลย

Tom Condo said...

มี 3 ตอนค่ะ เตรียมไว้เรียบร้อย รอฤกษ์ดี วางแผง
ว่าแต...จะ่มีภาค2 รึป่าวค่ะ @plaumkamon

^_^

Rice Cooker said...

@Kim ครับขอถามเอาฮา (จริงๆไม่รู้) TOC คืออะไรคับ
@Sanivipa คงไม่มีภาคต่อครับเพราะจบแล้ว แต่จะมีเรื่องอื่นแทนครับ

Unknown said...

@plaumkamon
- TOC ที่ว่าคือ Table of Content รึเปล่า
- ใช้ syntaxhighlighter ได้แล้วนะรองรับ css, java, js, sql, xml, php

Kim said...

TOC = Table of Content

Post a Comment