JAVA自定義註解的使用

JAVA反射

對於java來說,我們常見的功能都是類、屬性、方法,這些在我們常規變成中,起着舉足輕重的作用。但是JAVA之所以強大,反射機制纔是JAVA的重中之重,在之前幾章的博客中曾經提到利用JAVA的反射機制模擬mvc框架,模擬hibernate等數據庫框架。但是在反射過程中,還有一項非常重要的元素,那就是註解。

經常接觸spring的我們應該都瞭解,spring中代碼裏面註解有着極高的出場率,然而在什麼時候我們會需要使用註解,註解都能幫我們幹什麼,相信好多人對註解的理解還是比較模糊的。下面我們詳細瞭解一下註解

註解的定義

先引入一個比較調侃的話,“喬布斯重新定義了手機,羅永浩重新定義了傻逼”PS:這句話出自老羅的一個微博,本人無貶低老羅的意思。

首先讓我們來看看官方對註解的定義:

Java 註解用於爲 Java 代碼提供元數據。作爲元數據,註解不直接影響你的代碼執行,但也有一些類型的註解實際上可以用於這一目的。Java 註解是從 Java5 開始添加到 Java 的。

從過來人的角度上理解這句話,其實很簡單,但是從初學者的角度上來看,應該會是一頭霧水,那麼按照我的理解,註解應該這樣定義:

當你無法對已經定義好的類,屬性,方法進行改變;但是需求偏偏非要改變。那麼不能改變代碼,我們就去改變他的運行方式。

舉例:

比如數據庫定義好一個字段爲日期類型,框架約束好,日期的格式爲YYYY-MM-DD,但是偏偏有一個業務,必須要求日期要按照YYYY-MM-DD HH:MM:SS顯示。

在比如,我們定義好的對象中,有三個屬性,分別是name,age,sex。我們需要通過xml和其他系統進行交互,在我們自己使用的系統中,我們需要這三個字段,但是在和其他系統交互的時候,sex字段是隱私,我們不能給別人,但是我們還要使用這個對象。那麼在同其他系統交互過程中,轉爲xml的時候,我們就要忽略某個字段。

應用:

由於舉例中的第一個例子是SPRING MVC返回reponsebody中的常見問題,網上已經有很多解決方案,我們使用第二個例子進行解決

1、創建一個自定義註解類

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreXmlElement {
}

這是一個最基本的註解創建方式。當然我們註解裏面還有各種屬性,例如我們增加一個name的屬性,可以

String name() default "##default";

因爲第二個例子本身不需要太複雜的功能,我們暫時就不增加屬性了。

2、在我們需要轉換XML的類的某個屬性上增加上該註解

	@IgnoreXmlElement
	private String sex;

3、在類轉換xml的時候,根據註解對這個屬性特殊處理

	public String toString() {
		String xml = null;
		try {
			Class<T> c = getEntityClass();
			JAXBContext jc = JAXBContext.newInstance(c);
			Marshaller marshaller = jc.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_ENCODING, Encode.UTF8);
			marshaller.setListener(new MarshallerListener()); 
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			marshaller.marshal(this, bos);
			xml = new String(Base64.encodeBase64(bos.toByteArray()), Encode.UTF8);
		} catch (Exception e) {
			throw new RuntimeException("解析爲xml時出錯:" + e.getMessage());
		}
		return xml;
	}

在類中,我們重寫了類的toString方法,方便返回一個xml

marshaller.setListener(new MarshallerListener());

對xml的轉化我們這裏使用的java自帶的jaxbcontext,我們對齊增加一個監聽。

package com.easternie.sys.util;

import javax.xml.bind.Marshaller;

import com.easternie.his.webservice.model.data.IgnoreXmlElement;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

/**
 * 對java對象轉xml增加一個監聽,如果節點爲null空返回空節點
 * 
 * @author ZhangQiang
 *
 */
public class MarshallerListener extends Marshaller.Listener {
	public static final String BLANK_CHAR = "";

	@Override
	public void beforeMarshal(Object source) {
		super.beforeMarshal(source);
		Field[] fields = source.getClass().getDeclaredFields();
		for (Field f : fields) {
			f.setAccessible(true);
			Annotation an = f.getAnnotation(IgnoreXmlElement.class);
			if(an != null) {
				try {
					f.set(source, null);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}else {
				try {
					if (f.getType() == String.class && f.get(source) == null) {
						f.set(source, BLANK_CHAR);
					}
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
			
		}
	}
}

這個監聽實現瞭如下兩個功能,

功能一:如果我們通過反射獲取的field的註解不爲空,那麼說明這個字段是我們轉XML時候要忽略的,我們直接把他設置爲NULL,這裏要說明,在使用JAXBCONTEXT的過程中,我們可以給元素設置爲NULL讓其不產生XML節點。

功能二:但是如果是NULL就不顯示節點了,貌似又違背了我們的需求,我們主動設置爲NULL的應該不正常顯示,但是如果這個字段本身就爲NULL,我們應該給用戶返回一個空節點。所有又有了else中的代碼,我們增加一個空格,保證返回給用戶的是一個空節點,而非連節點都不顯示。

總結:

寫在最後,註解一般情況下都是結合反射使用,用來處理非常規流程的問題。所以在我們開發過程中遇到此類問題的時候。我們應該可以想到使用註解或者自定義註解,當然上面僅僅是舉例在屬性上增加註解,實際在類,在方法上增加註解獲取註解和上面代碼也大同小異,不再過多描述。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章