Difference between WebMvcConfigurationSupport and WebMvcConfigurerAdapter - spring

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 !!!

Related

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

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.

In spring should you create beans for existing classes?

I'm creating a spring application and I want to use an unaltered instance of SimpleUrlAuthenticationFailureHandler for use in my WebSecurityConfigurerAdapter class
.failureHandler(authFailureHandler)
Is it acceptable to use new SimpleUrlAuthenticationFailureHandler in this instance or should I create a bean in my appconfig to return the class? I feel like I should do it via Bean but I can't explain to my colleague exactly why this is.
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
vs
//in appconfig
#Bean
public FailureHandler failureHandler() {
return new SimpleUrlAuthenticationFailureHandler();
}
//back in the class
#Autowired
FailureHandler failureHandler
...
...
.failureHandler(failureHandler)
It may be acceptable, but using a bean enables: declaring it once and injecting it into several clients, hides the decision of which implementation is being used from the web security configuration, and allows for mocking in tests. Whether these concerns apply to your application is up to debate with your colleagues.

Spring Security - conditional WebApplicationInitializer

The documentation for Spring Security states that in order to use the Java Config we can extend the AbstractSecurityWebApplicationInitializer class which will set up all nesesarry beans for Spring Security to work. This approach is working fine, the initializer is run automatically and Spring Security is initialized correctly during application startup.
But right now i am facing a scenario when this initialization should be depended on a system property. So i would like to include my initializer class only when some system property is set (for example: app.enablesecurity=true) and NOT execute this initializer in any other case.
I failed to come up with any solution for that scenario because:
In AbstractSecurityWebApplicationInitializer the onStartup method is
marked final so i cannot override it and add a condition
If i just extend AbstractSecurityWebApplicationInitializer it is
always automatically picked up by Spring and instantiated (or at least Spring tries to create instance of it, it may fail), even if i
declare it as a private/inner/nested class.
So as far as i know the only possibility of conditionally including this initializer is to use cglib/javassist in order to dynamically create a class that extends AbstractSecurityWebApplicationInitializer.
Is there any other way? Maybe there is some method that will allow me to hide my implementation from being picked up by Spring and run it by hand at a later time?
You can use Config Class like this to configure your security behavior
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${app.enablesecurity}")
private boolean securityEnabled;
#Override
protected void configure(HttpSecurity http) throws Exception {
if (securityEnabled) {
http.csrf().disable();
...
} else {
http. ...
}
}
}

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.

When use AbstractAnnotationConfigDispatcherServletInitializer and WebApplicationInitializer?

I am working with Spring 4.0.7
I did a research about configure Spring MVC through JavaConfig.
Practically until yesterday I have seen two configurations using these two options
extends AbstractAnnotationConfigDispatcherServletInitializer
extends WebMvcConfigurerAdapter and implements WebApplicationInitializer
Note: (2) are two classes, one for extension and the other for implementation
I am using (2) because I have found many examples where I am able to configure converters, formatters, resources handlers etc…
But in the latest days I have tried to help a question on StackOverflow and I did realize (1) exists.. I did some overview on Google about (1) and exists some examples working with (1)
My question is how the title of this post describe.
Thank You
With the release of the Servlet 3.0 spec it became possible to configure your Servlet Container with (almost) no xml. For this there is the ServletContainerInitializer in the Servlet specification. In this class you can register filters, listeners, servlets etc. as you would traditionally do in a web.xml.
Spring provides a an implementation the SpringServletContainerInitializer which knows how to handle WebApplicationInitializer classes. Spring also provides a couple of base classes to extend to make your life easier and the AbstractAnnotationConfigDispatcherServletInitializer is one of those. It registers
a ContextLoaderlistener (optionally) and a DispatcherServlet and allows you to easily add configuration classes to load for both classes and to apply filters to the DispatcherServlet and to provide the servlet mapping.
The WebMvcConfigurerAdapter is for configuring Spring MVC, the replacement of the xml file loaded by the DispatcherServlet for configuring Spring MVC. The WebMvcConfigurerAdapter should be used for a #Configuration class.
#Configuration
#EnableWebMvc
public class WebConfiguration
extends WebMvcConfigurerAdapter implements WebApplicationInitializer
{ ... }
I wouldn't recommend mixing those as they are basically 2 different concerns. The first is for configuring the servlet container, the latter for configuring Spring MVC.
You would want to split those into 2 classes.
For the configuration.
#Configuration
#EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter { ... }
For bootstrapping the application.
public class MyWebApplicationInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer
{
protected Class<?>[] getRootConfigClasses() {
return new Class[] {RootConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[] {WebConfiguration .class};
}
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
An added advantage is that you now can use the convenience classes provided by Spring instead of manually configuring the DispatcherServlet and/or ContextLoaderListener.
To start from the beginning it is worth looking into how servlet container starts.
SpringServletContainerInitializer is bootstrapped automatically by any Servlet 3.0 container.
SpringServletContainerInitializer looks for classes implementing WebApplicationInitializer (link to spring.io; also well described in "Spring In Action" 4th edition by Craig Walls, p.135).
So to start - SpringServletContainerInitializer has to find the right class implementing WebApplicationInitializer. There are two ways of making it happen:
One is by implementing WebApplicationInitializer on its own; the interface was introduced in Spring 3.1
The second is by extending AbstractAnnotationConfigDispatcherServletInitializer class which also implements WebApplicationInitializer. The class was introduced in Spring 3.2 for convenience and it is "the preferred approach for applications that use Java-based Spring configuration." - see the link. It enables you to start servlet application context as well as root application context.
I would also like to higlight that WebMvcConfigurerAdapter you mention should not be confused with WebApplicationInitializer. As it name suggests - it has to do with configuring "Mvc". It is an adapter class that implements empty methods from WebMvcConfigurer. You use it when you configure your Mvc controller with #EnableWebMvc annotation.
Hope this helps.

Resources