Ở phần trước, các bạn đã được tìm hiểu về Java Reflection, ở phần này mình sẽ đề cập đến khái niệm khác nâng cao hơn cũng được phát triển từ Java Reflection. Đó là Annotation và cách tự tạo ra 1 annotation cho riêng mình.
Annotation được Java đưa ra từ phiên bản 1.5, tạo nên sự thay đổi lớn và là một phần quan trọng trong các framework hiện tại như Spring, Hibernate,… Những ai đã từng sử dụng Spring thì chắc chắn sẽ thấy các annotation như @Service, @Transaction,...
hay ở Hibernate thì sẽ thấy các annotation như @Key, @Entity,...
Hay annotation thường xuyên gặp nhất là @Override
. Đó là các annotation được xây dựng sẵn trong framework giúp người dùng thuận tiện trong việc khai báo các nghiệp vụ. Thay vì truyền tham số hay duplicate code để xử lý các nghiệp vụ tương tự nhau thì chỉ cần khai báo annotation cho class/field/method là xong.
Annotation thực chất là interface nên chỉ cần khai báo field hoặc method trong đó
Các annotation tự tạo sử dụng trong bài viết
Annotation Table định danh cho 1 entity tương đương 1 table như của hibernate
package net.tunghuynh.reflect.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) public @interface MyTable { String table(); String schema(); }
Annotation Field định danh cho 1 field là column của table
package net.tunghuynh.reflect.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) public @interface MyField { String column(); }
Annotation Key định danh cho 1 trường là Primary key. Cái này chỉ cần tạo annotation để khai báo, không cần field hay method nào thêm
package net.tunghuynh.reflect.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) public @interface MyKey { }
Annotation RequestMapping định danh cho 1 API path tương tự trong Spring boot
package net.tunghuynh.reflect.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) public @interface MyRequestMapping { String value(); String method(); }
Annotation Param định danh cho các parameter của method
package net.tunghuynh.reflect.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) public @interface MyParam { String value(); }
Ví dụ sử dụng annotation đã tạo cho class và field
package net.tunghuynh.reflect.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; /** * net.tunghuynh.reflect.annotation.EntityExample * by Tùng Huynh * at 28/01/2019 8:26 PM */ @MyTable(table = "table", schema = "schema") public class EntityExample { @MyKey @MyField(column = "COLUMN") private int column; public void printAnnotation(String... fields) throws Exception{ Class<?> aClass = getClass(); String keyColumn = ""; String sql = "SELECT "; for (int i = 0; i < fields.length; i++) { //Lấy danh sách column theo annotation Field field = aClass.getDeclaredField(fields[i]); MyField fieldAnn = field.getAnnotation(MyField.class); sql += fieldAnn.column() + ", "; //Tìm trường có chứa annotation MyKey Annotation[] fieldAnns = field.getAnnotations(); for (Annotation anno : fieldAnns) { if (anno instanceof MyKey){ keyColumn = fieldAnn.column(); break; } } } if (fields.length>0){ sql = sql.substring(0, sql.length()-2); } //Lấy annotation của class MyTable myAnn = aClass.getAnnotation(MyTable.class); sql += String.format(" FROM %s.%s WHERE 1=1", myAnn.schema(), myAnn.table()); System.out.println("Primary key: " + keyColumn); System.out.printf("SQL: " + sql); } public static void main(String[] args) throws Exception{ new EntityExample().printAnnotation("column"); } }
Kết quả khi chạy
Primary key: COLUMN SQL: SELECT COLUMN FROM schema.table WHERE 1=1
Ở đây mình chỉ viết mô phỏng in ra câu lệnh select, các bạn có thể phát triển các nghiệp vụ CRUD chi tiết hơn cho class
Giờ ta có thể tạo các entity khác kế thừa lại các nghiệp vụ chỉ bằng cách khai báo annotation rất đơn giản
package net.tunghuynh.reflect.annotation; /** * net.tunghuynh.reflect.annotation.StudentExample * by Tùng Huynh * at 28/01/2019 8:30 PM */ @MyTable(table = "STUDENT", schema = "QLSV") public class StudentExample extends EntityExample { @MyKey @MyField(column = "STUDENT_ID") private int studentId; @MyField(column = "NAME") private String name; public static void main(String[] args) throws Exception{ new StudentExample().printAnnotation("studentId", "name"); } }
Kết quả
Primary key: STUDENT_ID SQL: SELECT STUDENT_ID, NAME FROM QLSV.STUDENT WHERE 1=1
Ví dụ sử dụng annotation đã tạo cho method và parameter
package net.tunghuynh.reflect.annotation; import java.lang.reflect.Method; import java.lang.reflect.Parameter; /** * net.tunghuynh.reflect.annotation.MethodParameterExample * by Tùng Huynh * at 28/01/2019 8:27 PM */ public class MethodParameterExample { @MyRequestMapping(value = "/doMethod", method = "GET") protected void doMethod(@MyParam(value = "paramName") String paramValue) { } public void printAnnotation(String methodName, Class... paramTypes) throws Exception{ Class<?> aClass = getClass(); //Lấy đối tượng method Method method = aClass.getDeclaredMethod(methodName, paramTypes); // Lấy ra danh sách các Annotation của method. MyRequestMapping requestMapping = method.getAnnotation(MyRequestMapping.class); System.out.println(String.format("Method: %s | %s", requestMapping.value(), requestMapping.method())); // Lấy ra danh sách các Parameter của method. Parameter[] parameters = method.getParameters(); for (Parameter parameter : parameters) { MyParam myParam = parameter.getAnnotation(MyParam.class); System.out.println(myParam.value() + ": " + parameter.getName()); } } public static void main(String[] args) throws Exception{ new MethodParameterExample().printAnnotation("doMethod", String.class); } }
Kết quả
Method: /doMethod | GET paramName: arg0
Các bạn có thể tự tạo cho mình các Annotation riêng tùy theo nghiệp vụ và mục đích sử dụng, giúp thuận tiện hơn khi coding, giảm thiếu duplicate code dư thừa, tăng tốc code, tăng khả năng mở rộng và nhìn code chuyên nghiệp hơn.
Chúc các bạn thành công 🙂
Thật sự rất hay