Javaでカスタムアノテーションを作成する

1.はじめに

Javaアノテーションは、メタデータ情報をソースコードに追加するためのメカニズムです。これらはJavaの強力な部分であり、JDK5で追加されました。注釈は、XML記述子とマーカーインターフェイスの使用に代わるものを提供します。

それらをパッケージ、クラス、インターフェース、メソッド、およびフィールドにアタッチすることはできますが、アノテーション自体はプログラムの実行に影響を与えません。

このチュートリアルでは、カスタム注釈を作成する方法とそれらを処理する方法に焦点を当てます。アノテーションの詳細については、アノテーションの基本に関する記事をご覧ください。

2.カスタム注釈の作成

オブジェクトをJSON文字列にシリアル化することを目的として、3つのカスタムアノテーションを作成します。

クラスレベルで最初のものを使用して、オブジェクトをシリアル化できることをコンパイラに示します。次に、JSON文字列に含めるフィールドに2番目のフィールドを適用します。

最後に、メソッドレベルで3番目のアノテーションを使用して、オブジェクトの初期化に使用するメソッドを指定します。

2.1。クラスレベルのアノテーションの例

カスタムアノテーションを作成するための最初のステップは@ interfaceキーワードを使用してアノテーションを宣言することです。

public @interface JsonSerializable { }

次のステップは、メタアノテーション追加して、カスタムアノテーションのスコープとターゲットを指定することです。

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.Type) public @interface JsonSerializable { }

ご覧のとおり、最初のアノテーションには実行時の可視​​性があり、タイプ(クラス)に適用できます。さらに、メソッドがないため、JSONにシリアル化できるクラスをマークするための単純なマーカーとして機能します。

2.2。フィールドレベルの注釈の例

同様に、生成されたJSONに含めるフィールドをマークするために、2番目の注釈を作成します。

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface JsonElement { public String key() default ""; }

注釈は、「key」という名前の1つのStringパラメーターと、デフォルト値としての空の文字列を宣言します。

メソッドを使用してカスタムアノテーションを作成する場合、これらのメソッドにはパラメーターがあってはならず、例外をスローできないことに注意する必要があります。また、戻り値の型は、プリミティブ、文字列、クラス、列挙型、注釈、およびこれらの型の配列に制限されており、デフォルト値をnullにすることはできません

2.3。メソッドレベルのアノテーションの例

オブジェクトをJSON文字列にシリアル化する前に、オブジェクトを初期化するためのメソッドを実行したいとします。そのため、このメソッドをマークするアノテーションを作成します。

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Init { }

クラスのメソッドに適用できる実行時の可視​​性を備えたパブリックアノテーションを宣言しました。

2.4。注釈の適用

それでは、カスタムアノテーションをどのように使用できるかを見てみましょう。たとえば、JSON文字列にシリアル化するPersonタイプのオブジェクトがあるとします。このタイプには、姓名の最初の文字を大文字にするメソッドがあります。オブジェクトをシリアル化する前に、このメソッドを呼び出します。

@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オブジェクトをJSON文字列にシリアル化できることを示しています。さらに、出力には、そのオブジェクトのfirstNamelastName、およびageフィールドのみが含まれている必要があります。さらに、シリアル化の前にinitNames()メソッドを呼び出す必要があります。

@JsonElementアノテーションのキーパラメーターを「personAge」に設定することで、この名前をJSON出力のフィールドの識別子として使用することを示しています。

デモンストレーションのために、initNames()をプライベートにしたので、オブジェクトを手動で呼び出して初期化することはできず、コンストラクターもそれを使用していません。

3.注釈の処理

これまで、カスタムアノテーションを作成する方法と、それらを使用してPersonクラスを装飾する方法を見てきました。次に、JavaのReflectionAPIを使用してそれらを利用する方法を見ていきます。

最初のステップは、オブジェクトがnullであるかどうか、およびそのタイプに@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アノテーションが付いたメソッドを探し、それを実行してオブジェクトのフィールドを初期化します。

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); } } }

メソッドの呼び出し。setAccessibletrue)を使用すると、プライベートinitNames()メソッドを実行できます

初期化後、オブジェクトのフィールドを反復処理し、JSON要素のキーと値を取得して、それらをマップに配置します。次に、マップからJSON文字列を作成します。

private String getJsonString(Object object) throws Exception { Class clazz = object.getClass(); Map 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を使用しました。Personオブジェクトのフィールドはプライベートであるため、setAccessibletru e

JSONシリアライザークラスは、上記のすべての手順を組み合わせたものです。

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()); } } }

最後に、単体テストを実行して、カスタムアノテーションで定義されているようにオブジェクトがシリアル化されたことを検証します。

@Test public void givenObjectSerializedThenTrueReturned() throws JsonSerializationException { Person person = new Person("soufiane", "cheouati", "34"); JsonSerializer serializer = new JsonSerializer(); String jsonString = serializer.serialize(person); assertEquals( "{\"personAge\":\"34\",\"firstName\":\"Soufiane\",\"lastName\":\"Cheouati\"}", jsonString); }

4.結論

この記事では、さまざまなタイプのカスタムアノテーションを作成する方法を説明しました。次に、それらを使用してオブジェクトを装飾する方法について説明しました。最後に、JavaのReflectionAPIを使用してそれらを処理する方法を確認しました。

いつものように、完全なコードはGitHubで入手できます。