I want to use SpringBoot with Ebean. I found this article: http://ebean-orm.github.io/docs/setup/spring and I could set it up and make it work with an own implementation of a EbeanServerFactory as shown in the article.
It states, that if I add ebean-spring to my dependencies along with a default-ebean-server.xml than it should work with a default EbeanServerFactoryBean. But what should I write to this file? Where do I set up the FactoryBean to use my datasource etc.? Sorry if my question is silly, but I am really new to SpringBoot and don't understand it deeply.
If I add ebean-spring and remove my own factory I get an error:
No qualifying bean of type [com.avaje.ebean.EbeanServer] found for dependency
So I could solve it after a day of thinking, and trying. In Spring you usually have an Application.java or something which starts your app with your main(). Here you can define a EbeanServer Factory like the following:
#Bean
public EbeanServerFactoryBean ebeanServerFactoryBean() {
EbeanServerFactoryBean ebeanServerFactoryBean = new EbeanServerFactoryBean();
ServerConfig config = new ServerConfig();
config.setName("pg");
config.loadFromProperties();
//other configs
config.setDefaultServer(true);
ebeanServerFactoryBean.setServerConfig(config);
return ebeanServerFactoryBean;
}
Related
Lets say i have two beans:
class MyBean implements BeanInterface(){}
class MyBean2 implements BeanInterface(){}
And if specific property exists, i want to create MyBean, otherwise I want to create MyBean2(). How can i do this?
#Bean
#ConditionalOnProperty(name = "property.validation")
public BeanInterface beanInterface() {
return new MyBean();
}
works if I want to create MyBean if property exists, but how do I create MyBean2 if it doesn't?
#Bean
#ConditionalOnMissingBean(MyBean.class)
public BeanInterface beanInterface() {
return new MyBean2();
}
complains that method with same name exists, and if i understand it correctly, the methods name need to be camelCase name of the bean.
How do i do this?
Thanks
//edit i tried:
#Bean
#ConditionalOnProperty(name = "property.validation")
#Order(1)
public BeanInterface beanInterface() {
return new MyBean();
}
#Bean("beanInterface")
#ConditionalOnMissingBean(MyBean.class)
#Order(2)
public BeanInterface beanInterface() {
return new MyBean2();
}
but it didnt work, second bean is not getting created when property is missing.
You can specify bean name #Bean("beanInterface") then method name can be anything.
You have Java configuration at your hands, so use that to your advantage. Not everything needs annotations to be fixed.
#Bean
public BeanInterface myBean(Environment env) {
String validation = env.getProperty("property.validation", String.class);
return validation != null ? new MyBean(validation) : new MyBean2();
}
The name of the method doesn't matter it can be anything you like.
Spring and Spring boot provide a a following solution: If you need to choose one implementation of the interface at runtime, than you inject all implementations and choose appropriate one at runtime. Assuming that you have an interface DataSource with multiple implementations here is how you inject them all:
#Autowired
private List<DataSource> dataSources;
You can read about this solution here.
This is a standard solution, but I really don't like it as it is waistful to inject all implementations. So, I wrote a feature that is available as part of MgntUtils open-source library. That feature allows you to create a static factory per each interface, and once you add any implementation of that interface declared as a Bean, that implementation will be added automatically at start up into a relevant factory. So, instead of injecting all implementations in your class you at runtime take from the factory needed implementation. I think it is much more elegant solution, and it has been battle-tested and it works well. Here is Javadoc that explains the concept and has a detailed example on how to use it: Lifecycle management. Also here is the article that describes this feature in detail: Non-intrusive access to "Orphaned" Beans in Spring framework. The library is available as Maven artifact at Maven central ad also on Github including javadoc and source code. In the source code there is a working example on how to use this feature
My problem references to this issue here on github https://github.com/mapstruct/mapstruct/issues/1427
I got at least two versions of mappers with the same name. I want to use springs getBean/Autowired possibilities but this doesn't work out of the mapstructs box yet. :-)
I followed the second workaround mentioned in the upper link: extend Springs bean naming strategy. Did someone ever get this well ment proposal working?
If i follow the code parts from there the bean naming doesn't take place. For me its's clear why not: there aren't any components to scan and especially to find.
If i add a componenModel = "spring" to the mapper annotation i get a ConflictingBeanDefinitionException. Don't know why. Maybe there's a cat in the tail problem?
As stated from Filip here https://github.com/mapstruct/mapstruct/issues/1427 i followed his approach and with a few modifications it worked. I added a solution comment in the link.
The main changes are:
i added componentModel = "spring" to my mappers and used a filter to exclude all of my mapper classes (the interface all of my mappers are implementing: MapperInterface.class) within the Spring Boot application.
To my Spring Boot application class i added:
#ComponentScan(basePackages = { "com.application.spring_boot_class" }, excludeFilters = { #ComponentScan.Filter(value = { MapperInterface.class }, type = FilterType.ASSIGNABLE_TYPE) })
I had this issue before, and I resolved it using the Spring bean definition in a configuration class, a class annotated with #Configuration, with the Mapstruct mapper call like below:
#Bean
public IMyMapper offerWebMapper() {
return Mappers.getMapper(IMyMapper.class);
}
And then you can inject the mapper using #Autowired or getBean.
I'm looking for a way to follow source of spring configuration from annotation.
E.g. Having below Bean is any way to e.g. click on my-components-service.books.configurations and be redirect or list yaml files which contains config which would be injected in runtime?
#Bean
#ConfigurationProperties(prefix = "my-components-service.books.configurations")
Map<ComponentType, BooksConfiguration> booksConfiguration() {
return new HashMap<>();
}
If #ConfigurationProperties is at the class level then there should be some gutter icons that will show where the properties have been set.
It doesn't look like this works when it's specified on a #Bean like in your example however. A possible workaround is to use a nested #Configuration class, though that may be undesirable.
I'm trying to make a custom spring boot starter that will be used by multiple projects to authenticate with Azure AD. All the Azure AD config has been set up and an individual project hardcoded with all the settings to work with Azure AD works fine too. Now I'm trying to move these settings into a custom Spring Boot starter so that multiple projects can use it. It works for the most part, except for one thing: moving the bean config for a custom AADAppRoleStatelessAuthenticationFilter. If I leave my custom implementation (CustomAADAppRoleStatelessAuthFilter) hardcoded in the actual implementing project, everything works and only CustomAADAppRoleStatelessAuthFilter is created, but as soon as I move it into the custom starter, I only ever get AADAppRoleStatelessAuthenticationFilter instead.
Note that my CustomAADAppRoleStatelessAuthFilter extends the starter's
AADAppRoleStatelessAuthenticationFilter.
The autoconfig for AADAppRoleStatelessAuthenticationFilter in the azure-spring-boot project (https://github.com/microsoft/azure-spring-boot/blob/master/azure-spring-boot/src/main/java/com/microsoft/azure/spring/autoconfigure/aad/AADAuthenticationFilterAutoConfiguration.java) is:
#Bean
#ConditionalOnMissingBean(AADAppRoleStatelessAuthenticationFilter.class)
#ConditionalOnProperty(prefix = PROPERTY_PREFIX, value = PROPERTY_SESSION_STATELESS, havingValue = "true")
public AADAppRoleStatelessAuthenticationFilter azureADStatelessAuthFilter(ResourceRetriever resourceRetriever) {
//bean details omitted
}
My custom autoconfig that should replace the above is as follows:
#Bean
#ConditionalOnMissingBean(AADAppRoleStatelessAuthenticationFilter.class)
#ConditionalOnProperty(prefix = PROPERTY_PREFIX, value = PROPERTY_SESSION_STATELESS, havingValue = "true")
public AADAppRoleStatelessAuthenticationFilter customAADAppRoleStatelessAuthFilter(
ResourceRetriever resourceRetriever) {
return new CustomAADAppRoleStatelessAuthenticationFilter(/*details omitted*/);
}
No amount of #AutoConfigureBefore(AADAuthenticationFilterAutoConfiguration.class) works.
Also, if I change the condition on my custom bean to be the subtype (#ConditionalOnMissingBean(CustomAADAppRoleStatelessAuthFilter.class)), BOTH types get created, and I can autowire my CustomAwareAADAppRoleStatelessAuthFilter and put it in my WebSecurityConfigurerAdapter, but things STILL won't work. I debugged things and found that the CustomAADAppRoleStatelessAuthFilter is the only bean of the ADAppRoleStatelessAuthenticationFilter type in my spring security filter chain, but that once the 'end of the additional filter chain' has completed and the 'original chain proceeds', I find that the ADAppRoleStatelessAuthenticationFilter has fired! And of course it throws an error because my CustomAADAppRoleStatelessAuthFilter has already done things to customize the UserPrincipal. I can't figure out where the ADAppRoleStatelessAuthenticationFilter is getting added to any filter chain, and even if I mark my CustomAADAppRoleStatelessAuthFilter bean with #Primary, the starter ADAppRoleStatelessAuthenticationFilter will still be used instead.
The only 'solutions' that have worked are to define the CustomAADAppRoleStatelessAuthFilter in the actual implementing project instead of the custom starter project, or to exclude the AADAuthenticationFilterAutoConfiguration in my actual implementing project's #SpringBootApplication annotation (Not even excluding it the property-based way works).
Is there a way to make AADAuthenticationFilterAutoConfigurations ADAppRoleStatelessAuthenticationFilter bean definition back off? 'Cause #AutoConfigureBefore(AADAuthenticationFilterAutoConfiguration.class) on my custom auto configuration class that has my CustomAADAppRoleStatelessAuthFilter definition doesn't work, and having all the implementing projects explicitly exclude AADAuthenticationFilterAutoConfiguration isn't the most ideal solution (although at least with that solution they don't all need to declare their own bean definition for CustomAADAppRoleStatelessAuthFilter).
Have you tried using #Order and assign your custom bean a higer precedence. By default all the beans gets lowest priority (Ordered.LOWEST_PRECEDENCE) losing to any other specified order value.
#Order(Ordered.LOWEST_PRECEDENCE - 1)
#Bean
#ConditionalOnMissingBean(AADAppRoleStatelessAuthenticationFilter.class)
#ConditionalOnProperty(prefix = PROPERTY_PREFIX, value = PROPERTY_SESSION_STATELESS, havingValue = "true")
public AADAppRoleStatelessAuthenticationFilter customAADAppRoleStatelessAuthFilter(
ResourceRetriever resourceRetriever) {
return new CustomAADAppRoleStatelessAuthenticationFilter(/*details omitted*/);
}
Can you try putting the #Order(Ordered.LOWEST_PRECEDENCE - 1) like i mentioned above? Your bean should then take precedence over the other.
Have you tried adding #Primary to your bean?
Just wondering what is the correct way to inject a map in my Application.java file to be used in services in other classes using the Spring Java Config approach
If i setup 1 bean like this
#Bean(name = "databaseScheduler")
public SchedulerFactoryBean databaseScheduler() {
...
...
}
And reference if later like this then everything works as expected
#Inject
private SchedulerFactoryBean databaseScheduler;
But when I try and setup a map of SchedulerFactoryBeans as follows
#Bean(name = "databaseSchedulersMap")
public Map<Integer, SchedulerFactoryBean> databaseSchedulersMap() {
....
....
}
And inject it later like so
#Resource
private Map<Integer, SchedulerFactoryBean> databaseSchedulersMap;
It doesnt work and properties on the bean are missing or null
Im setting up the SchedulerFactoryBean in the exact same manner as the single bean instance but its proving really difficult to get this going
Any help on this is greatly appreciated
Apologies #Ma Kro
I tried your suggestion again with the #Resource(name="databaseSchedulersMap") and it worked
I must have had a typo in it the first time or something
Sorry about that