DEV Community

André Laugks
André Laugks

Posted on

Using nested annotations for key-value pairs in a custom annotation

Introduction

In my article "Using a hashmap in a custom annotation" I explained how to use a HashMap in an annotation using an Enum Constant.

Nested annotations can also be used to map key-value pairs.

List of supported Types in Annotations

Annotations

Two customs annotations are required. The first annotation (e.g. MapItem) containing a key-value pair and the second annotation (e.g. MapItems) containing a list of MapItem annotations.

Custom Annotation @MapItem

The annotation @MapItem represents a single key-value pair.

@Target(ElementType.FIELD)
public @interface MapItem {

    String key();
    String value();
}
Enter fullscreen mode Exit fullscreen mode

Custom Annotation @MapItems

The annotation @MapItems defines a list of MapItem.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MapItems {

    MapItem[] items();
}
Enter fullscreen mode Exit fullscreen mode

Functional Test

The list of @MapItem annotations are set in the @MapItems annotation.

class ExampleDto {

    @MapItems(items = {
        @MapItem(key = "1", value = "MALE"),
        @MapItem(key = "2", value = "FEMALE"),
        @MapItem(key = "6", value = "DIVERS")
    })
    public String salutation;
}
Enter fullscreen mode Exit fullscreen mode

The MapItemsTest tests the MapItems annotation. The test is done on the salutation field.

To demonstrate how the list of @MapItem can be used, I create a HashMap from @MapItem and compare it to an expected HashMap.

class MapItemsTest {

    @Test
    void testMapItems() throws NoSuchFieldException {

        Field field = ExampleDto.class.getDeclaredField("salutation");
        field.setAccessible(true);

        MapItems annotation = field.getAnnotation(MapItems.class);

        Map<String, String> mappingItems = Arrays
                .stream(annotation.items())
                .collect(
                    Collectors.toMap(
                        MapItem::key,
                        MapItem::value
                    )
        );

        assertEquals(
            new HashMap<>() {{
                put("1", "MALE");
                put("2", "FEMALE");
                put("6", "DIVERS");
            }},
            mappingItems
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Pro

It is a smart solution and easy to implement.

Contra

If the key-value pairs are to be used in a validator, for example, they must be fetched indirectly.

Full example

https://github.com/alaugks/article-annotation-key-value-pairs

Related article

Top comments (0)