更新時(shí)間:2022-07-01 11:05:54 來源:動(dòng)力節(jié)點(diǎn) 瀏覽2852次
如何創(chuàng)建Java自定義注解?動(dòng)力節(jié)點(diǎn)小編來為大家解答。Java 中的注釋是一種將元數(shù)據(jù)信息添加到我們的源代碼的機(jī)制。它們是 JDK5 中添加的 Java 的一個(gè)強(qiáng)大部分。注釋提供了使用 XML 描述符和標(biāo)記接口的替代方法。
雖然我們可以將它們附加到包、類、接口、方法和字段上,但注釋本身對(duì)程序的執(zhí)行沒有影響。
在本教程中,我們將重點(diǎn)介紹如何創(chuàng)建和處理自定義注釋。我們可以在關(guān)于注釋基礎(chǔ)的文章中閱讀更多關(guān)于注釋的信息。
我們將創(chuàng)建三個(gè)自定義注釋,目標(biāo)是將對(duì)象序列化為 JSON 字符串。
我們將在類級(jí)別使用第一個(gè),向編譯器指示我們的對(duì)象可以被序列化。然后我們將第二個(gè)應(yīng)用到我們想要包含在 JSON 字符串中的字段。
1.類級(jí)別注釋示例
創(chuàng)建自定義注解的第一步是使用@interface關(guān)鍵字聲明它:
public @interface JsonSerializable {
}
下一步是添加元注釋來指定我們自定義注釋的范圍和目標(biāo):
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.Type)
public @interface JsonSerializable {
}
如我們所見,我們的第一個(gè)注解具有運(yùn)行時(shí)可見性,我們可以將其應(yīng)用于類型(類)。此外,它沒有方法,因此可以作為一個(gè)簡(jiǎn)單的標(biāo)記來標(biāo)記可以序列化為 JSON 的類。
(2)字段級(jí)注釋示例
以同樣的方式,我們創(chuàng)建第二個(gè)注釋來標(biāo)記我們將包含在生成的 JSON 中的字段:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonElement {
public String key() default "";
}
注釋聲明了一個(gè)名為“key”的字符串參數(shù)和一個(gè)空字符串作為默認(rèn)值。
在使用方法創(chuàng)建自定義注解時(shí),我們應(yīng)該注意這些方法必須沒有參數(shù),并且不能拋出異常。此外,返回類型僅限于這些類型的基元、字符串、類、枚舉、注釋和數(shù)組, 默認(rèn)值不能為 null。
(3)方法級(jí)別注釋示例
假設(shè)在將對(duì)象序列化為 JSON 字符串之前,我們想要執(zhí)行一些方法來初始化對(duì)象。出于這個(gè)原因,我們將創(chuàng)建一個(gè)注釋來標(biāo)記這個(gè)方法:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Init {
}
我們聲明了一個(gè)具有運(yùn)行時(shí)可見性的公共注釋,我們可以將其應(yīng)用于類的方法。
(4)應(yīng)用注釋
現(xiàn)在讓我們看看如何使用我們的自定義注解。例如,假設(shè)我們有一個(gè)Person類型的對(duì)象 ,我們想將其序列化為 JSON 字符串。這種類型有一個(gè)方法可以將名字和姓氏的第一個(gè)字母大寫。我們需要在序列化對(duì)象之前調(diào)用這個(gè)方法:
@JsonSerializable
public class Person {
@JsonElement
private String firstName;
@JsonElement
private String lastName;
@JsonElement(key = "personAge")
private String age;
private String address;
@Init
private void initNames() {
this.firstName = this.firstName.substring(0, 1).toUpperCase()
+ this.firstName.substring(1);
this.lastName = this.lastName.substring(0, 1).toUpperCase()
+ this.lastName.substring(1);
}
// Standard getters and setters
}
通過使用我們的自定義注釋,我們表明我們可以將 Person 對(duì)象序列化為 JSON 字符串。此外,輸出應(yīng)僅包含該對(duì)象的firstName、lastName和age字段。此外,我們希望在序列化之前調(diào)用initNames()方法。
通過將@JsonElement注釋的關(guān)鍵參數(shù)設(shè)置為“personAge”,我們表明我們將使用此名稱作為JSON 輸出中字段的標(biāo)識(shí)符。
為了演示,我們將initNames() 設(shè)為私有,因此我們不能通過手動(dòng)調(diào)用來初始化我們的對(duì)象,而且我們的構(gòu)造函數(shù)也沒有使用它。
到目前為止,我們已經(jīng)了解了如何創(chuàng)建自定義注釋,以及如何使用它們來裝飾Person類。現(xiàn)在我們將了解如何通過使用 Java 的反射 API 來利用它們。
第一步是檢查我們的對(duì)象是否為空,以及它的類型是否有 @JsonSerializable注解:
private void checkIfSerializable(Object object) {
if (Objects.isNull(object)) {
throw new JsonSerializationException("The object to serialize is null");
}
Class<?> clazz = object.getClass();
if (!clazz.isAnnotationPresent(JsonSerializable.class)) {
throw new JsonSerializationException("The class "
+ clazz.getSimpleName()
+ " is not annotated with JsonSerializable");
}
}
然后我們尋找任何帶有@Init 注解的方法,并執(zhí)行它來初始化我們對(duì)象的字段:
private void initializeObject(Object object) throws Exception {
Class<?> clazz = object.getClass();
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Init.class)) {
method.setAccessible(true);
method.invoke(object);
}
}
}
方法的調(diào)用 。setAccessible ( true)允許我們執(zhí)行私有的initNames()方法。
初始化后,我們遍歷對(duì)象的字段,檢索 JSON 元素的鍵和值,并將它們放入映射中。然后我們從地圖創(chuàng)建 JSON 字符串:
private String getJsonString(Object object) throws Exception {
Class<?> clazz = object.getClass();
Map<String, String> jsonElementsMap = new HashMap<>();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
if (field.isAnnotationPresent(JsonElement.class)) {
jsonElementsMap.put(getKey(field), (String) field.get(object));
}
}
String jsonString = jsonElementsMap.entrySet()
.stream()
.map(entry -> "\"" + entry.getKey() + "\":\""
+ entry.getValue() + "\"")
.collect(Collectors.joining(","));
return "{" + jsonString + "}";
}
同樣,我們使用了 field。setAccessible ( true )因?yàn)镻erson對(duì)象的字段是私有的。
我們的 JSON 序列化程序類結(jié)合了上述所有步驟:
public class ObjectToJsonConverter {
public String convertToJson(Object object) throws JsonSerializationException {
try {
checkIfSerializable(object);
initializeObject(object);
return getJsonString(object);
} catch (Exception e) {
throw new JsonSerializationException(e.getMessage());
}
}
}
最后,我們運(yùn)行一個(gè)單元測(cè)試來驗(yàn)證我們的對(duì)象是否按照自定義注釋的定義進(jìn)行了序列化:
@Test
public void givenObjectSerializedThenTrueReturned() throws JsonSerializationException {
Person person = new Person("soufiane", "cheouati", "34");
ObjectToJsonConverter serializer = new ObjectToJsonConverter();
String jsonString = serializer.convertToJson(person);
assertEquals(
"{\"personAge\":\"34\",\"firstName\":\"Soufiane\",\"lastName\":\"Cheouati\"}",
jsonString);
}
以上就是關(guān)于“創(chuàng)建Java自定義注解”的介紹,大家如果對(duì)此比較感興趣,想了解更多相關(guān)知識(shí),不妨來關(guān)注一下動(dòng)力節(jié)點(diǎn)的Java開發(fā)自定義注解,里面有更詳細(xì)的介紹,希望對(duì)大家能夠有所幫助哦。
相關(guān)閱讀
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)