DEV Community

André Laugks
André Laugks

Posted on • Edited 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.

Annotations are allowed as type in an annotation. This means that nested annotations can be used to define key-value pairs in a custom annotation.

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

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay