Why cannot I use #ConfigurationProperties instead of #Value in Spring WebConfig - java

I want to configure my WebConfig bean to have different CORS origin depending on the profileapplication.properties.
For some reason the value in my application-local.properties is not injected into the field of my WebConfig bean.
When I use #Value here it will work (please check last headline for the working example)
Entry Class
#SpringBootApplication
#EnableEurekaClient
#ComponentScan("com.company.coma")
public class EventWebApplication {
public static void main(String[] args) {
SpringApplication.run(EventWebApplication.class, args);
}
}
WebConfig.java
#Configuration
#ConfigurationProperties("coma.cors")
public class WebConfig extends WebMvcConfigurerAdapter {
private String origin;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping(Resources.Services.APIs.Event.GET_STATUS + "/**")
.allowedOrigins(origin);
}
}
application-local.properties
coma.cors.origin=http://localhost:8080
Execution
starting the application with -Dspring.profiles.active=local
Result
Working example
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Value("${coma.cors.origin}") // this works
private String origin;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping(Resources.Services.APIs.Event.GET_STATUS + "/**")
.allowedOrigins(origin);
}
}

Related

#Order annotation vs FilterRegistrationBean.setOrder vs addFilterBefore/addFilterAfter in WebSecurityConfigurerAdapter.configure

I am adding filters in my application and I want to set the order of call for these filters. I can see three ways but I don't know if they're at all related?
Using #Order annotation:
#Component
#Order(1)
public class SampleFilter extends OncePerRequestFilter {
...
}
Register the filter via config:
#Configuration
public class FilterConfig {
#Bean
public FilterRegistrationBean<SampleFilter> perfFilter() {
FilterRegistrationBean<SampleFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new SampleFilter());
registration.setOrder(1);
return registration;
}
}
Via WebSecurityConfigurerAdapter:
public class SampleConfig extends WebSecurityConfigurerAdapter {
#Autowired
private SampleFilter sampleFilter;
#Override
public void configure(HttpSecurity http) throws Exception {
...
http.addFilterBefore(this.sampleFilter, SampleFilterTwo.class);
}
}

Initializa Bean with YAML configuration in Spring Boot

I would like to read some properties, like DB access configs, when initializing bean or service in spring boot.
Anyone knows good ways ?
This is my current code snippet.
public class SampleApplication implements ApplicationRunner
{
#Autowired
private YAMLConfig myConfig;
#Override
public void run(ApplicationArguments args) throws Exception
{
System.out.println(myConfig != null); //YAMLConfig has been intialized here
}
public SampleApplication()
{
System.out.println(myConfig == null); //myConfig is null
}
#Configuration
public static class Config
{
#Bean
#ConditionalOnProperty(value = {"batch.execute"}, havingValue = "SampleApplication")
public SampleApplication sampleApplication()
{
return new SampleApplication();
}
}
}
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties
public class YAMLConfig
{
private String environment;
public String getEnvironment()
{
return environment;
}
public void setEnvironment(String environment)
{
this.environment = environment;
}
}
Thanks for taking a look at this!
create this method inside your SampleApplication class
#PostConstruct
public void init() {
// at this point, all the dependency injection has happened already
myConfig.doStuff()
}
it will be called by spring automatically after all bean initialization has been done.

Turn POJO to #Configuration programmatically Spring

Given a class:
class MyConfiguration {
#Bean
String bean() {
return new String();
}
}
as you may notice it does not have #Configuration annotation.
How can I make it behave like it has #Configuration annotation, but not adding it?
#Bean annotation should not work in Lite Mode, https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html
Something like:
#Configuration
class MainConfiguration {
#Bean
MyConfiguration myConfiguration() {
MyConfiguration myConfiguration = do_some_spring_magic();
// myConfiguration behaving like it's having #Configuration here
return myConfiguration;
}
}
I dont understand what is the use case you are trying to achieve here.. But if you are looking for programatically registering beans into the Spring Context then you can do it as below.
#Configuration
public class MyBeanRegisterFactory implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanRegistry) throws BeansException {
//depending on some condition you can do the below line
beanRegistry.registerBeanDefinition("myBeanClass", new RootBeanDefinition("com.mybean.MyBeanClass"));
}
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
In Your case, the bean definitions inside the class MyConfiguration can be programatically registered as below into to the spring context.
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/support/BeanDefinitionRegistryPostProcessor.html

Spring addFormatters not called of WebMvcConfigurerAdapter

I'm trying to implement a converter in a Spring Boot app but for some reason my override of addFormatters(FormatterRegistry formatterRegistry) is never called. What's confusing is that other overridden methods are called, addInterceptors works just fine. Security is enabled for this app.
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {"com.company.web"})
public class WebMvcConfig extends WebMvcConfigurerAdapter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
#Inject
private TenantIdentifierInterceptorAdapter multiTenancyInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
logger.info("adding interceptor");
registry.addInterceptor(multiTenancyInterceptor);
}
//THIS IS NOT CALLED
#Override
public void addFormatters(FormatterRegistry formatterRegistry) {
logger.info("adding converters");
formatterRegistry.addConverter(new StringToPersonConverter());
}
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {"classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/"};
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS)
.setCachePeriod(3600).resourceChain(true).addResolver(new PathResourceResolver());
}
#PostConstruct
public void init() {
requestMappingHandlerAdapter.setIgnoreDefaultModelOnRedirect(true);
}
}
For some reason if I add this code to the file the formatter code is hit, but I get an error "A ServletContext is required to configure default servlet handling" and the app won't compile.
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
Have you configured a bean with super class WebMvcConfigurationSupport?
If you did so, it will disable WebMvcAutoConfiguration Bootstrap.
Check this code:
#Configuration
#ConditionalOnWebApplication(
type = Type.SERVLET
)
#ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
#ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
#AutoConfigureOrder(-2147483638)
#AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
I'm not 100% sure but did you try to remove #EnableWebMvc annotation from the class? Because according to documentation it shouldn't be there:
If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own #Configuration class of type WebMvcConfigurerAdapter, but without #EnableWebMvc.
M. Deinum's comment was the answer. I've removed #EnableWebMvc and removed the method addFormatters, then added:
#Bean
StringToPersonConverter stringToPersonConverter() {
return new StringToPersonConverter();
}
I have solved a similar error
EnableWebMvc
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Documented
#Import(DelegatingWebMvcConfiguration.class)
public #interface EnableWebMvc {
}
DelegatingWebMvcConfiguration
#Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
#Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
//...
#Override
protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
}
//...
}
WebMvcConfigurationSupport
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
//...
#Bean
public FormattingConversionService mvcConversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
addFormatters(conversionService);
return conversionService;
}
/**
* Override this method to add custom {#link Converter}s and {#link Formatter}s.
*/
protected void addFormatters(FormatterRegistry registry) {
}
//...
}
My custom config with multiple WebMvcConfigurerAdapter implements WebMvcConfigurer
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter
{
#Autowired
private ConversionService conversionService;
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers)
{
argumentResolvers.add(new RequestTenantResolverComposite(conversionService));
}
}
The method will not be called if the FormattingConversionService implements ConversionService bean created before WebMvcConfigurer injected.
I solved my question using Lazy annotion for ConversionService with spring verions 4.3.6.

#Autowired fails in spring boot web project

I have a simple Spring Boot web project, right from a template:
#SpringBootApplication
#RestController
public class HelloWorldRestApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorldRestApplication.class, args);
Performer p = new Performer();
p.perform();
}
}
I have a test to ensure autowiring works, and in fact it does in this test class (examples come from Spring in Action, 4th):
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {
#Autowired
private CDPlayer cdp;
#Test
public void cdShouldNotBeNull(){
assertNotNull(cdp);
}
}
and:
public class Performer {
#Autowired
private CDPlayer cdp;
public void perform(){
System.out.println(cdp);
cdp.play();
}
public CDPlayer getCdp() {
return cdp;
}
public void setCdp(CDPlayer cdp) {
this.cdp = cdp;
}
}
and:
#Component
public class CDPlayer{
public void play(){
System.out.println("play");
}
}
config:
#Configuration
#ComponentScan
public class CDPlayerConfig {
}
However, it doesnt work in HelloWorldRestApplication, I get null.
Adding #ContextConfiguration(classes=CDPlayerConfig.class) doesn't help.
What do I miss?
Try enabling #ComponentScan your packages in your main class and get Performer class instance from ApplicationContext as below:
#SpringBootApplication
#RestController
#ComponentScan({“package.name.1”,”package.name.2”})
public class HelloWorldRestApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(HelloWorldRestApplication.class, args);
Performer p = ctx.getBean(Performer.class);//get the bean by type
p.perform();
}
}

Categories

Resources