1

i am writting a framework and I need to pass some information from an annotation to a PostConstruct method.

What iam currently failing at is getting the data in a nice way.

How can i get from here:

@EnableCoolFeature(data1="foo", data2="bar")
public class MainApp {
    public static void main (){ //SpringApp init etc }
}

To here:

@Configuration
public class CoolFeatureConfiguration{

    @PostConstruct
    void processData(){
        //how to get the data in here?
    }
}

Also note that the user can enable "@EnableCoolFeature" multiple times on different Configurations

EDIT: i found a way which works for me

var beanNamesForAnnotation = applicationContext.getBeansWithAnnotation(EnableCoolFeature.class);

for (var tuple : beanNamesForAnnotation.entrySet()) {
    var result = applicationContext.findAnnotationOnBean(tuple.getKey(), EnableCoolFeature.class);
    //the magic!
}
Loading
  • 1,098
  • 1
  • 12
  • 25

1 Answers1

2

An example can be found here.

You need to implement something like this:

import java.lang.annotation.Annotation;
import org.springframework.core.annotation.AnnotationUtils;

@EnableCoolFeature(data1 = "foo", data2 = "bar")
public class MainApp {

  public static void main ()
  {
    try {
      Annotation enableCoolFeatureAnnotation = AnnotationUtils.findAnnotation(MainApp.class, EnableCoolFeature.class);
      System.out.println("@EnableCoolFeature of MainApp.class is: "+enableCoolFeatureAnnotation);

      System.out.println("@EnableCoolFeature value: "+AnnotationUtils.getValue(enableCoolFeatureAnnotation));
      System.out.println("@EnableCoolFeature default value data1: "+AnnotationUtils.getDefaultValue(enableCoolFeatureAnnotation, "data1"));
      System.out.println("@EnableCoolFeature default value data2: "+AnnotationUtils.getDefaultValue(enableCoolFeatureAnnotation, "data2"));
      System.out.println("@EnableCoolFeature data1: "+AnnotationUtils.getValue(enableCoolFeatureAnnotation, "data1"));
      System.out.println("@EnableCoolFeature data2: "+AnnotationUtils.getValue(enableCoolFeatureAnnotation, "data2"));
      
      String data1 = (String)AnnotationUtils.getValue(enableCoolFeatureAnnotation, "data1");
      String data2 = (String)AnnotationUtils.getValue(enableCoolFeatureAnnotation, "data2");
      
      // ... pass the arguments to Spring Boot: https://www.baeldung.com/spring-boot-command-line-arguments
      String[] args = { data1, data2 };
      SpringApplication.run(MainApp.class, args);
      
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Edit: As the author asked how could unknown annotations be processed dynamically, here is an example. Before the code above can be executed, we need to retrieve the annotation classes and the field names according to a defined criteria. Paste the following code right after try { in the code above:

    try {
        MergedAnnotations mas = MergedAnnotations.from(MainApp.class);
        for (MergedAnnotation<Annotation> ma : mas)
        {
            Class<Annotation> annotationClass = ma.getType();
            
            Field[] fields = annotationClass.getFields();
            
            for (Field field:fields)
            {
                String fieldName = field.getName();
                
                // Retrieve the values as shown below with data1 and data2 but this time using annotationClass and fieldName. 
            }
        }
    ....

In the original code example MainApp.class must be replaced by a parameter Class<?> appClass that must be supplied by your users when they call the main() method from their code. Or a better solution would be to rename the method and make it an instance method (not static), then let your users inherit from MainApp and then you can use directly getClass() to get your user's app class:

// This is part of your framework:
public class MainApp {

  protected void runSpring() {
     // ... same code
  }
}

// This is the code your users would have to write:
@EnableCoolFeature(data1 = "foo", data2 = "bar")
public class YourUsersApp extends MainApp {
    
  public static void main ()
  {
    new YourUsersApp().runSpring();
  }
}
D-FENS
  • 1,438
  • 8
  • 21
  • 1
    Thanks for the answer, but this is not so easy, as your code assumes that you know the class with the annotation, but iam writing a library and the user adds the annotation to any configuration, so i dont know the class at compiletime – Loading Dec 04 '21 at 14:26
  • Well, then you can use `getAnnotations()` instead of `findAnnotation()` and just loop until you find what you are looking for. Then pass it to Spring. Instead of MainApp.class, use `getClass()` and let the user inherit your MainApp class, then in `main()` they need to call `super.main()`. I will post an example. – D-FENS Dec 04 '21 at 14:31
  • I posted some examples, I believe this should be enough to achieve your goal. – D-FENS Dec 04 '21 at 14:46
  • Thanks for your example, but this is still not what iam really asking: I dont want that the user has to do any "workarounds", just annotate a single "mainClass" with the @EnableCoolFeature and he is done. My framework now needs to look for this annotation and do the rest. I currently did something like that, by iterating over all beans and looking for the annotation. There is a small problem, as this annotation is not on a spring configuration, but on the main method. – Loading Dec 04 '21 at 14:55
  • Well, this is exactly what I am proposing. Your users have to create 1 class with 1 static method and 1 line of code just calling your `runSpring()` method. The rest they implement is only annotations. `MainApp` is supposed to be a part of your framework. – D-FENS Dec 04 '21 at 14:59
  • 1
    I found a solution, i edited the question with the solution. Thanks for your help anyway! – Loading Dec 04 '21 at 15:13
  • 1
    Cool, thanks for sharing the answer. I think I misunderstood your goal, I thought the user could provide their own custom annotations and @EnableCoolFeature is simply an example. But if you control the annotation class, then you know in advance what kinds of attributes they can pass. Good luck! – D-FENS Dec 04 '21 at 15:16