Spring MVC #Value/#ConfigurationProperties working on MainConfig but not on SecurityConfig - spring

I have a simple Spring MVC 5 project, with security layer enabled. Everything works good except the properties loading, only on Security Config.
I let you the scenario so you can see it.
application.properties (located at src/main/resources)
com.company.myapp.prop=myprop
MainConfig.java
#Configuration
public class MainConfig implements WebMvcConfigurer {
#Value("${com.company.myapp.prop}")
private String prop;
#Bean
public MySpecialBean mySpecialBean() {
System.out.println(prop); // output > myprop
return new MySpecialBean();
}
}
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${com.company.myapp.prop}")
private String prop;
#Bean
public MySpecialSecurityBean mySpecialSecurityBean() {
System.out.println(prop); // output > null
return new MySpecialSecurityBean();
}
}
I don't understand why it's happening. I already switched the #EnableWebSecurity annotation to the app class, try to set the PropertySourcesPlaceholderConfigurer myself, but nothing works.
Do you have any idea what's going on?

From official docs about #PropertySource:
Resolving ${...} placeholders in <bean> and #Value annotations
In order to resolve ${...} placeholders in definitions or #Value annotations using properties from a PropertySource, you must ensure that an appropriate embedded value resolver is registered in the BeanFactory used by the ApplicationContext. This happens automatically when using in XML. When using #Configuration classes this can be achieved by explicitly registering a PropertySourcesPlaceholderConfigurer via a static #Bean method. Note, however, that explicit registration of a PropertySourcesPlaceholderConfigurer via a static #Bean method is typically only required if you need to customize configuration such as the placeholder syntax, etc. See the "Working with externalized values" section of #Configuration's javadocs and "a note on BeanFactoryPostProcessor-returning #Bean methods" of #Bean's javadocs for details and examples.
You should try to add annotation #PropertySource into the your config class.
#Configuration
#PropertySource("classpath:my.properties")
public class MainConfig implements WebMvcConfigurer {}
and then try to access your property in SecurityConfig class
To get full information see official docs
I hope it will help you

This works for me.
I guess you have another class that triggers the application and that is annotated with #SpringBootApplication
Also, your methods mySpecialBean do not return a MySpecialBean instance, so this probably does not even compile.
Is there any other class that you are using? Please advice

Finally got it!
The problem was related with some dependency priorities and unnecessary beans declarations. Getting into details, I'm working with OAuht2 and I started with this tutorial. In the end I've made a mix with this one too (more recent). The problem was related with these #Bean's that don't really need to be declared as beans:
ClientRegistrationRepository
ClientRegistration
OAuth2AuthorizedClientService
Spring was calling these beans before any other configuration, so any properties was not loaded yet. Maybe changing the priority, dependence or even the order would resolve the issue, but as I was analysing the code I found that these methods are only used on security configuration and not really needed along any other part of the app. So I removed the #Bean declaration and all works nice now! At the time these methods are called inside security config the properties are already loaded.
Hope to help someone out there.

Related

Split jackson configuration into separate properties

I'm using Spring Boot 2.2.5.RELEASE and would like to split my application.properties into separate files. There are already similar questions on StackOverflow but none of them seem to work for configuring Jackson.
My current non working solution is the following:
root/
- application.properties (without Jackson configuration)
- jackson-configuration.properties (includes Jackson configuration)
Jackson configuration class:
#Configuration
#PropertySource("/jackson-configuration.properties")
public class JacksonConfiguration {
}
Please note, I've tried different ways to specify the path including:
"/jackson-configuration.properties"
"jackson-configuration.properties"
"classpath:/jackson-configuration.properties"
"classpath:jackson-configuration.properties"
Spring Boot does not seem to use the configuration. If I copy it over into the application.properties - it works.
Content of jackson-configuration.properties:
spring.jackson.property-naming-strategy=SNAKE_CASE
spring.jackson.mapper.sort-properties-alphabetically=true
spring.jackson.deserialization.fail-on-unknown-properties=true
spring.jackson.parser.strict-duplicate-detection=true
spring.jackson.time-zone=Europe/Zurich
My application is annotated with #SpringBootApplication , so it should scan for additional properties.
/edit
I just realized the problem is the testing, not the productive code itself. If I start the application it works. What doess not work is testing with #JsonTest. I can fix this problem by adding the following line to my tests #ContextConfiguration(classes = {JacksonConfiguration.class}). But in turn, this causes the annotation #JsonComponent to stop working but only for the #JsonTest annotated classes.
See the documentation here. Here is an excerpt from the documentation
In order to resolve ${...} placeholders in definitions or
#Value annotations using properties from a PropertySource, you must
ensure that an appropriate embedded value resolver is registered in
the BeanFactory used by the ApplicationContext. This happens
automatically when using in XML. When
using #Configuration classes this can be achieved by explicitly
registering a PropertySourcesPlaceholderConfigurer via a static #Bean
method.
You need to create a bean like this
#Bean
public static PropertySourcesPlaceholderConfigurer devPropertyPlaceholderConfigurer() throws IOException {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setLocations(new PathMatchingResourcePatternResolver().getResources("file:pathtToFile"));
configurer.setIgnoreUnresolvablePlaceholders(true);
return configurer;
}

Spring Bean Overriding My ObjectMapper Configuration

Had an issue today where a dependency wired with a configuration kept winning when it came to some ObjectMapper configuration I was trying to do. I added the following to my Spring Boot application.
#Configuration
public class CustomObjectMapperConfig {
#Autowired
public void configureObjectMapper(ObjectMapper objectMapper) {
objectMapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
}
I'd actually rather not use timestamps, but for backwards compatibility I had to do this. I put a debug point at the line in question here and it got hit, but I kept getting dates returned to me in ISO format, which is the default for most or our projects.
I finally figured out that a company dependency that I was bringing in had the following:
#Configuration
public class ObjectMapperPropertiesConfig {
/**
* #deprecated Spring boot jackson properties should be used instead.
*/
#Deprecated
#Autowired
public void setObjectMapper(
final ObjectMapper objectMapper) {
objectMapper
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, !ignoreUnknown);
}
...
This class was getting loaded after my class, so it alwasy won with regards to the WRITE_DATES_AS_TIMESTAMPS feature.
To fix this I ended up adding a #DependsOn annotation. This forced the other bean to load first giving my bean the chance to win the configuration war. Finding the correct name of the bean was difficult. It ended up looking something like this:
#DependsOn("path.to.object.ObjectMapperPropertiesConfig")
Note: The #Deprecated annotation here tell me that this code will be going away in future versions in favor of spring boot properties anyway. For now, my change will work.

Is constructor injection possible in Spring configuration classes?

If I have a Spring configuration class (i.e. a class annotated with #Configuration) can I use constructor injection ?
As it stands if I add one I get a no default constructor message, and if I add a default constructor it uses that rather than the overloaded one, which doesn't really help.
There is a bug report about this limitation. It will be fixed with Spring 4.3.
Please note that another bug report (not fixed yet today fixed in 4.3-RC1) report a problem when using this very new feature and injecting generics in constructor of a #Configuration class.
In Spring 4.3, you can use org.springframework.beans.factory.ObjectProvider in #Configuration annotated class constructors to inject beans. for example:
#Configuration
public class SimpleBean {
private final InnerBean prop1;
public Simple Bean(ObjectProvider<InnerBean> innerBeanProvider) {
prop1 = innerBeanProvider.getObject();
}
}

The annotation #EnableSpringDataWebSupport does not work with WebMvcConfigurationSupport?

I had been using the WebMvcConfigurerAdapter for a while. Since i could not get all the registered interceptors with the method getInterceptors(), i have switched to WebMvcConfigurationSupport, which has lot of default registered Spring Beans like ContentNegotiationManager, ExceptionHandlerExceptionResolver usw.
Now i have realised that, the very handy DomainClassConverter (which converts the domain class ids to domain class objects by using a CrudRepository) is not registered by default, although i use the annotation #EnableSpringDataWebSupport on my WebConfig class.
When i define this bean explicitly like this, it works then.
#EnableSpringDataWebSupport
#Configuration
public class WebConfig extends WebMvcConfigurationSupport {
#Bean
public DomainClassConverter<?> domainClassConverter() {
return new DomainClassConverter<FormattingConversionService>(mvcConversionService());
}
}
But why EnableSpringDataWebSupport does not work with WebMvcConfigurationSupport?
It looks like configuration classes that extend WebMvcConfigurationSupport directly suffer from SPR-10565. The solution, at least for me, is to extend from DelegatingWebMvcConfiguration instead.
If you're overriding individual callbacks in your configuration class you'll likely want to call the superclass' implementation of the callback as well to ensure it's all handled correctly.

Difference between WebMvcConfigurationSupport and WebMvcConfigurerAdapter

I would like to add resource handlers. In the forum they use WebMvcConfigurationSupport: http://forum.springsource.org/showthread.php?116068-How-to-configure-lt-mvc-resources-gt-mapping-to-take-precedence-over-RequestMapping&p=384066#post384066
and docs say WebMvcConfigurerAdapter: http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html
What's the difference and which one to use? Both has the addResourceHandlers method I need.
This is my current class:
#Configuration
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
public #Override void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources");
}
public #Bean TilesViewResolver tilesViewResolver() {
return new TilesViewResolver();
}
public #Bean TilesConfigurer tilesConfigurer() {
TilesConfigurer ret = new TilesConfigurer();
ret.setDefinitions(new String[] { "classpath:tiles.xml" });
return ret;
}
}
The answer is in the doc you referenced above:
If the customization options of WebMvcConfigurer do not expose
something you need to configure, consider removing the #EnableWebMvc
annotation and extending directly from WebMvcConfigurationSupport
overriding selected #Bean methods
In short, if #EnableWebMvc works for you, there is no need to look any further.
if you use ConfigurationSupport class get ready mind numbing hardwork when trying to serve static resources, because it does not work.
I was recently solving this very same problem when configuring converters and it resulted in quite a long post.
By default Spring Boot uses its implementation of WebMvcConfigurationSupport and does a lot of auto-magic including finding all the WebMvcConfigurer and using them. There is one implementation provided by Boot already and you may add more. This results in seemingly confusing behaviour when the list of converters coming to configureMessageConverters in your implementation of WebMvcConfigurer is already pre-populated from previous configurer.
These types (WebMvcConfigurationSupport and WebMvcConfigurer) have also strikingly similar interface - but the first does NOT implement the other. The point is:
Support class searches for configurers and uses them + does something on its own.
If you extend from WebMvcConfigurationSupport you take over the configuration and while there are some things available that are not in WebMvcConfigurer (like addDefaultHttpMessageConverters) there is also tons of code from EnableWebMvcConfiguration and DelegatingWebMvcConfiguration that does not happen.
Both extending WebMvcConfigurationSupport or WebMvcConfigurer (not sure both at once makes much sense) have their valid usages, but with extending the support class you take over the process much more and lose a lot of "opinionated" Spring Boot functionality.
Its better to extend WebMvcConfigurationSupport. It provides more customization options and also
works fine with
configureMessageConverters(List<HttpMessageConverter<?>> converters)
cause you can add these convertors using
addDefaultHttpMessageConverters(converters);
that is not available with WebMvcConfigurerAdapter.
Click [here] How to configure MappingJacksonHttpMessageConverter while using spring annotation-based configuration?
If you extend WebMvcConfigurerAdapter, it behaves strangely with configuring Jackson and Jaxb.
That happened with me !!!

Resources