When you want to dynamically replace Annotation in Java8

background

It's not a very common story, but you may want to dynamically change a class that has annotations like @Data (key = "1") to @Data (key = "2").

solution

Java8 seems to have additional functions in such cases, so I referred to the following site.

A little simpler

public class DynamicAnnotationReplaceUtils {
    private static final String ANNOTATIONS = "annotations";
    private static final String ANNOTATION_DATA = "annotationData";

    /**
     *Replaces an annotation of one class with another annotation.
     *
     * @since
     *
     * @param targetClazz This class sets the annotation to be replaced.
     * @param originalOne Annotation of the replacement source.
     * @param newOne Annotation to replace. It will often be an instance of a class that extends the annotation of the replacement source.
     */
  public static void annotationReplacedBy(Class<?> targetClazz, String originalName, Annotation newOne) {
        try {
            @SuppressWarnings("all")
            Method method = Class.class.getDeclaredMethod(ANNOTATION_DATA, null);
            method.setAccessible(true);

            Object annotationData = method.invoke(targetClazz);

            Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS);
            annotations.setAccessible(true);

            @SuppressWarnings("unchecked")
            Map<Class<? extends Annotation>, Annotation> map =
                    (Map<Class<? extends Annotation>, Annotation>) annotations.get(annotationData);

            Annotation original = map.entrySet().stream().filter(e -> {
                return e.getKey().getSimpleName().equals(originalName());
            }).findFirst().get().getValue();

            if (original == null) {
                throw new IllegalArgumentException(
                        String.format("Class(%s) has not %s annotaion.",
                                targetClazz.getCanonicalName(), originalName));
            }

            map.put(original, newOne);
        } catch (Exception ex) {
            throw new IllegalArgumentException(ex);
        }
    }

How to Use

DynamicAnnotationReplaceUtils.annotationReplacedBy(AnnotatedCalss.class, "Data", new ReplacedData()), 

What is the annotation to replace?

Definition of replacement source annotation

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Data {
    public abstract String key();
}

Definition of replacement annotation

public ReplacedData implements Data {
    public  String key() {
         return "2";
    }
}

Class with substitution source annotation

@Data(key = "1")
public TestData() {
}

Recommended Posts

When you want to dynamically replace Annotation in Java8
When you want to bind InputStream in JDBI3
A note when you want Tuple in Java
[Ruby] When you want to replace multiple characters
How to dynamically switch JDK when building Java in Gradle
Code to use when you want to process Json with only standard library in Java
ProxyFactory is convenient when you want to test AOP in Spring!
Use JLine when you want to handle keystrokes on the console character by character in Java
When you want to implement Java library testing in Spock with multi-module in Gradle in Android Studio 3
(Limited to Java 7 or later) I want you to compare objects in Objects.equals
If you want to dynamically embed values & add text to attribute values in Thymeleaf 3
I want to get the IP address when connecting to Wi-Fi in Java
I want to send an email in Java.
When you want to use the method outside
rsync4j --I want to touch rsync in Java.
[Swift] Use nonzeroBitCount when you want popcnt in Swift
What to do when you think you can't do Groovy-> Java in IntelliJ IDEA CE
When you want to notify an error somewhere when using graphql-spring-boot in Spring Boot
I want to do something like "cls" in Java
I want to use ES2015 in Java too! → (´ ・ ω ・ `)
If you want to recreate the instance in cloud9
You don't have to write for twice when you make a right triangle in Java
Code used when you want to process Json with only the standard library in Java (improved version) gson unnecessary
To you who suffer from unexpected decimal points in Java
Java study site summary that you want to read carefully
[# 3 Java] Read this if you want to study Java! ~ Carefully selected ~
Things you often use when doing web development in Java
When you want to explicitly write OR or AND with ransack
Things to be aware of when writing code in Java
Even in Java, I want to output true with a == 1 && a == 2 && a == 3
When you want to change the MySQL password of docker-compose
docker-compose.yml when you want to keep mysql running with docker
lombok.config when you want to pass @Qualifier to @RequiredArgsConstructor with lombok
Delegate is convenient to use when you want to reuse parts
I want to simplify the conditional if-else statement in Java
[Ruby + Rails] When you want to register in Mailchimp's mail list together with user registration
How to write in Model class when you want to save binary data in DB with PlayFramework
When you want to reflect the Master Branch information in the Current Branch you are currently working on
[Swift] When you want to know if the number of characters in a String matches a certain number ...
In Java 10, when you do gradle eclipse and JavaSE-1.10 comes out, ...
Comparison of version strings (Java implementation) when you want to branch the process between two versions
Multithreaded to fit in [Java] template
How to write when you want to keep line breaks and output while avoiding XSS in Rails
Object-oriented design that can be used when you want to return a response in form format
<java> When "EXCEPTION_ACCESS_VIOLATION" appears in awt
Read CSV in Java (Super CSV Annotation)
How to learn JAVA in 7 days
If you want to include the parent class in Lombok's @builder
When you want to ZIP download the image data saved locally
If you want to change the Java development environment from Eclipse
Log output to file in Java
How to write when you want to handle "array of C language strings" like argv [] in Ruby-FFI
Setting that converts to binding.pry when you type pry in VScode
What to do when you want to know the source position where the method is defined in binding.pry
[Docker] Magic command when you want to wipe out none image
I made an annotation in Java.
How to use classes in Java?
How to name variables in Java
[Java] I want to perform distinct with the key in the object
How to solve the unknown error when using slf4j in Java
Try to implement Yubaba in Java