Spring boot: create configuration properties bean in runtime - java

Is there a way to create #ConfigurationProperties beans in runtime using spring's functionality?
Let's say I want to state the prefixes in my custom annotation and create beans for them in runtime because creating them manually seems like a boiler-plate to me.
Something like this:
#MyAnnotation({
#CustomProps(prefix="foo"),
#CustomProps(prefix="bar")
})
And then in runtime, I want to have two config beans of the specified type created from properties with these prefixes.
I know I can generate code for them using an annotation processor, but maybe it's easier to achieve by spring's bean processors or something like this?

Yes! you can achieve it but you can't have class fields for each property. So, easy approach is use spring annotation processor and for fields you can use map which you could map using Environment bean.
https://www.baeldung.com/spring-annotation-bean-pre-processor blog would be helpful in understanding how it works with annotation processor.
(Here)[Spring: access all Environment properties as a Map or Properties object you can see how to get map of properties.

Related

Use class annotation to run on class initialization with Spring AOP

Is it possible to create a Java aspect that runs on class initialization using Spring AOP?
We have an annotation that will be used in several places, and in order to make use of the annotation we need some boilerplate code that needs to run every second (using #Scheduled). We're hoping to move that boilerplate code to another class-level annotation to make it easier to reuse.
As far as I understand, it's not possible to implement such a class-level annotation using Spring AOP since it only supports method execution (https://www.baeldung.com/spring-aop-vs-aspectj#4-joinpoints). Is there any workaround to achieve what we're hoping for? I'm aware we could use AspectJ instead of Spring AOP, but I'm reluctant to do that because it's complex to use.
Code snipped:
#Scheduled(fixedDelayString = "${app.pollable-consumer.time-interval}")
public void pollForDeletionRequest() {
log.trace("Polling for new messages");
cleanupInput.poll(cleanupSubmissionService::submitDeletion);
}
Thanks for your help.
Update: The annotation needs to be added to a library to enable it to be shared by different microservices.
We think that writing a new class-level annotation might help. It would run on class initialization, find all methods that are annotated with #PollableStreamListener, and schedule the polling to happen for each of the Kafka topics.
To slightly adjust the terminology and shift the focus, is it acceptable to bind the creation of such a construction to Spring's Application Context initialization? If so, you could create a Bean Factory Post Processor that would have been triggered for each #PollableStreamListener.
In a nutshell, BFPP runs before spring creates the beans during the application context initialization. This mechanism allows to "dynamically" create beans that in a runtime will be indistinguishable from those created by spring in a regular way, a kind of hook to the spring initialization lifecycle that you can use here.
So this BFPP and introspect the methods of your interest. Then based on the information found in the annotations / configuration This BFPP could register a Bean Definition per scheduled job of the bean (a class with all the required parameters that you could prepare as a part of the infrastructure). Then spring will read this bean definition and create the beans out of this bean definition as it usually does.
Here you can find an example of how to use this BFPP and more specifically its registerBeanDefintion method.

Overriding spring properties in test with computed values

I know I can use #TestPropertySource. But annotations accept only literals. what if i want to compute the values or even if i want to compute which properties i want to override. is it doable in spring? how can i register arbitrary properties in spring's Environment in tests?
You can use spring profiles to load up a configuration object. By encapsulating the configuration you can compute the values to use in test profile.

Declare my own annotaion

As you know when I want to inject a class to my class's property in spring framework I do something like this:
Class sample {
#Autowired
MyService service;
}
or use #Resource or #Named or what else.
but now I wonder that if possible I declare my own annotation like #MyInjection to do this stuff and besides do something more.
for example, instead of searching the application context and find proper bean to inject, create a class and inject this created bean to property of class.
Thanks.
An annotation is just basically data about data. So if you want something to handle your annotation you have to write a custom annotation processor.
I suggest you should look into Spring's AOP features for more details:
Aspect Oriented Programming with Spring
With AOP you basically create an annotation (in your case) then you configure Spring to do something when it bumps into your annotation (Spring uses regexps for this if I remember it right). This is called a Pointcut. Then if Spring finds a match it runs your custom code which can be basically anything.
I think what you want could be achieved by using Spring's factory method, which gets called when Spring is about to resolve some dependency. See example Hope this helps.

PropertyPlaceholderConfigurer to look for DB values and use properties file as fallback

I'm wondering if its possible to use the value in DB before properties file in PropertyPlaceholderConfigurer. So what I want to achieve is to load the properties file, and if any keys exist in the database, use that. Right now I don't know where to start, but I'm assuming that there is a method/class that I can override or interface that I need to implement.
Just mention the method/class/interface and I will gladly start from there. TIA
PropertyPlaceholderConfigurer has a "properties" property that can point to an object that retrieves the database values. See an example here: http://pure-essence.net/2011/02/10/spring-loading-properties-from-database-with-a-twist/
Also, you'll want to set "ignoreUnresolvablePlaceholders" to true on the bean that config that loads the properties from the database. That way you can add another PropertyPlaceholderConfigurer as a fallback to provide properties that are not found in the database.
Since you want to merge properties, you may want to implement InitializingBean on your target bean. Your hook will be the afterPropertiesSet method, where you can go about with your kung-fu.
BTW, Spring loads and overrides beans definitions in the order the container encounters it.

Multiple Bean Configurations of a Class

I have 2 beans configured for a class so that I can configure the class with two different data layer implementations. What I'm wondering is if there is a pattern or best practice for selecting between the two different beans in my code. I know without Spring, the Factory pattern would be commonly used for this, but it seems a bit redundant being as beans are retrieved from Spring via a factory.
There's no problem having a Factory within a Factory. It happens all the time in Spring, in fact. I'd say that sounds like a good approach here. Your data storage factory would be a Spring bean and be injected with the two different implementations, which are also beans. The job of the factory is to choose between them based on some input.
Declare both beans and mark one as primary. You can either use:
<bean primary="true" ...
in XML configuration or:
#Primary
#Bean
In #Configuration approach. Spring will prefer primary beans when performing autowiring. Reference documentation.

Categories