I was unreasonable enough to went into configuring spring beans via annotations and not pure xml beans and now I'm facing the consequences.
I configure REST channels using
<mvc:annotation-driven />
Now I want simply configure the MappingJacksonHttpMessageConverter to output to JSON only this fields that have non-null values. I've tried the following:
<bean id="jsonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="prefixJson" value="false" />
<property name="supportedMediaTypes" value="application/json" />
<property name="objectMapper">
<bean class="org.codehaus.jackson.map.ObjectMapper">
<property name="serializationInclusion" value="NON_NULL"/>
</bean>
</property>
</bean>
The beans gets created, but another instance of converter is created and used in channels. So I've tried the way with #Configuration and #Bean described in this Stackoverflow question, but still json serialization uses its own configuration.
Finally I've tried to inject the mapper via
#Autowired
private MappingJacksonHttpMessageConverter jacksonConverter;
but I've ended with NoSuchBeanDefinitionException. So now I'm out of options and therefore I'm asking for any ideas here. How to controll and configure the mapper used by framework?
Use the WebMvcConfigurer.configureMessageConverters() method:
Configure the HttpMessageConverters to use [...] If no message converters are added to the list, default converters are added instead.
With #Configuration you have:
#Configuration
class MvcConf extends WebMvcConfigurationSupport {
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
addDefaultHttpMessageConverters(converters);
}
#Bean
MappingJacksonHttpMessageConverter converter() {
MappingJacksonHttpMessageConverter converter = new MappingJacksonHttpMessageConverter()
//do your customizations here...
return converter;
}
}
Call to addDefaultHttpMessageConverters() is required because the defaults are not applied when using custom converters.
IMPORTANT NOTE You must remove #EnableWebMvc for your converters to be configured if you extend WebMvcConfigurationSupport.
The customization of the spring mvc servlet configuration only in java code can be accomplished in multiple ways.
The simplest one seems to be extending your #Configuration annotated class with WebMvcConfigurerAdapter:
#Configuration
#EnableWebMvc
public class ApplicationSpringConfig extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters( List<HttpMessageConverter<?>> converters ) {
converters.add(converter());
}
#Bean
MappingJackson2HttpMessageConverter converter() {
// [...]
}
}
Notice that this is lot like the example provided by the answer of Tomasz Nurkiewicz.
However using WebMvcConfigurationSupport instead of WebMvcConfigurerAdapter is more appropriate for Advanced Customizations. That was the case if you needed to also add the default converters.
See the Spring documentation Customizing the Provided Configuration
The following solution is for Spring 4.3, (non-boot) where it was necessary to address fetch=FetchType.LAZY by adding a module to the Jackson converters. A similar technique can be used to modify converters in any way, including removal and recreation.
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> mc : converters){
if (mc instanceof MappingJackson2HttpMessageConverter || mc instanceof MappingJackson2XmlHttpMessageConverter) {
((AbstractJackson2HttpMessageConverter) mc).getObjectMapper().registerModule(new Hibernate5Module());
}
}
return;
}
In this case,
the WebMvcConfigurerAdapter has a lot of other configuration in it and I wanted to avoid another configuration class.
Using extendMessageConverters enabled access to the automatically-configured Jackson classes without losing the configuration of all other message converters, which is what configureMessageConverters would have done.
Using registerModuleyou can simply add the needed Hibernate5Module to the existing converters.
The module was added to both the JSON and XML processors
Related
Given the following Java class
#Order(12)
#Component
public class MyComponent {
//....
}
what is the equivalent in the Spring XML configuration? I couldn't find anything matching the #Order annotation for the XML based configuration:
<bean class="MyComponent" />
In spring you have 2 choices:
annotation
interface implementation
In your case you will have to go with the second option.
Your class needs to implement Ordered, but this will bind your class with spring API. It's same when using annotation over class.
But if you are using configuration classes, instead of xml config, then you can have plain java beans, and keep all Spring API in configurations.
Example:
#Bean(destroyMethod = "shutdown")
#Order(12)
public ScheduledExecutorService scheduledExecutorService() {
return Executors.newSingleThreadScheduledExecutor();
}
Configuration classes give you the option to separate Spring API(annotations) from your beans.
I want to specify in property file, which bean will be autowired.
I found the solutions but all of them are using #Profile annotation, which means that they are based on specified profile, not specified property.
I did it in that way:
#Configuration
public class WebServiceFactory {
#Value("${webservice}")
private String webService;
#Lazy
#Autowired
private GraphQLService graphQLService;
#Lazy
#Autowired
private RestService restService;
#Primary
#Bean
WebService getWebService() {
switch (webService) {
case "graphQlService":
return graphQLService;
case "restService":
return restService;
default:
throw new UnsupportedOperationException("Not supported web service.");
}
}
}
Bean type I want to autowire is interface WebService, GraphQLService and RestService are it's implementations.
Is there any better way to do this?
You can do this using the normal configuration of Spring.
class A{
B bBean;
...//setters/getters here.
}
class B{}
You can have a configuration file (It also can be a configuration class)
<bean id = "a" class = "A">
<property name="bBean" ref="b"/>
</bean>
<bean id = "b" class = "B">
</bean>
The bBean configuration can be in a different file, so you can import it from you classpath. Instead of using a property file you use a configuration file in the classpath o systemfile. If B is a different implementation then you modify your config file with the right class.
I would like to use #PreAuthorize annotations to secure methods in Spring REST controller, using method parameters, e.g.
#RequestMapping("/something/{myParam}")
#PreAuthorize("#security.check(#myParam)")
public String getSomething(#PathVariable("myParam") Integer myParam) {
//...
}
Spring Security needs a way to discover param names in runtime. When there is no debugging symbols in the compiled class, it is necessary to add a special annotation #P or Spring Data's #Param. So, the method would look like this:
#RequestMapping("/something/{myParam}")
#PreAuthorize("#security.check(#myParam)")
public String getSomething(#PathVariable("myParam") #P("myParam) Integer myParam) {
//...
}
Is it possible to somehow hint Spring Security to use #PathVariable instead and avoid additional annotations like #P?
According to the documentation reading parameter names from annotations is done by AnnotationParameterNameDiscoverer which can be customized to support the value attribute of any specified annotation. However, I could not find any information on how to customize it.
BTW, I'm using Java 7 and Spring Security 3.2.9.
In short, you need to override creating of SecurityExpressionHandler in the method GlobalMethodSecurityConfiguration#createExpressionHandler so that set your own ParameterNameDiscoverer in custom GlobalMethodSecurityConfiguration.
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Autowired
private ApplicationContext context;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler result = new DefaultMethodSecurityExpressionHandler();
result.setApplicationContext(this.context);
result.setParameterNameDiscoverer(new AnnotationParameterNameDiscoverer(PathVariable.class.getName()));
return result;
}
}
In the sample project you can see result in console output something like this
2016-06-06 17:09:01.635 INFO 2871 --- [nio-8080-exec-4] c.s.so.q37435824.SecurityService: myParam value from PathVariable equals 1
Best regards
From the official Spring security docs GlobalMethodSecurityConfiguration
Sometimes you may need to perform operations that are more complicated
than are possible with the #EnableGlobalMethodSecurity annotation
allow. For these instances, you can extend the
GlobalMethodSecurityConfiguration ensuring that the
#EnableGlobalMethodSecurity annotation is present on your subclass.
For example, if you wanted to provide a custom
MethodSecurityExpressionHandler, you could use the following
configuration:
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
// ... create and return custom MethodSecurityExpressionHandler ...
return expressionHandler;
}
}
As in the above example you can write your custom MethodSecurityExpressionHandler or use the DefaultMethodSecurityExpressionHandler and set your custom ParameterNameDiscoverer extending the DefaultSecurityParameterNameDiscoverer (or not)
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setParameterNameDiscoverer(new CustomParameterNameDiscoverer());
return expressionHandler;
}
}
One more example Spring Security Java Config Preview: Custom Method Security
Hope this helps.
Following configuration was not tested, but based on research of sources of spring security, so try to change your Spring Security configuration xml as follows
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="parameterNameDiscoverer" ref="parameterNameDiscoverer"/>
</bean>
<bean id="parameterNameDiscoverer" class="org.springframework.security.core.parameters.AnnotationParameterNameDiscoverer">
<constructor-arg>
<list>
<value>org.springframework.web.bind.annotation.PathVariable</value>
</list>
</constructor-arg>
</bean>
From Spring security official documentation the requested usecase can be achieved . But to use you need to upgrade to spring 4.1.0, I didn't tried by looks like this is achievable
I am working on a project with multiple spring configuration java classes. Many of them have beans from other config classes autowired in and then injected in the constructors of other beans.
To make this as flexible as possible, I have been using spring profiles to define which implementation of an interface to use in the case where multiple are available.
This works fine, but I was wondering if there was any way with Spring that you could define a default bean?
For example: If no bean of type Foo found on classpath, inject implementation Bar. Else, ignore Bar.
I have looked at this question: Spring 3: Inject Default Bean Unless Another Bean Present, and the solution shown with Java config would work fine if you knew the name of all of the beans, but in my case I will not know what the beans are called.
Does anybody know of a way this can be achieved?
Define the default as, well the default, just make sure that the name of the bean is the same, the one inside the profile will override the default one.
<beans>
<!-- The default datasource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
</bean>
<beans profile="jndi">
<jndi:lookup id="dataSource" jndi-name="jdbc/db" />
</beans>
</beans>
This construct would also work with Java based config.
#Configuration
public DefaultConfig {
#Bean
public DataSource dataSource() { ... }
#Configuration
#Profile("jndi")
public static class JndiConfig {
#Bean
public DataSource dataSource() { ... // JNDI lookup }
}
}
When using java based configuration you can also specify a default and in another configuration add another bean of that type and annotate it with #Primary. When multiple instances are found the one with #Primary should be used.
#Configuration
public DefaultConfig {
#Bean
public DataSource dataSource() { ... }
}
#Configuration
#Profile("jndi")
public class JndiConfig {
#Bean
#Primary
public DataSource jndiDataSource() { ... // JNDI lookup }
}
How can I achieve something similar to this:
<jee:jndi-lookup id="datasSource"
jndi-name="jdbc/dataSourceName" expected-type="javax.sql.DataSource" />
<tx:jta-transaction-manager/>
Using annotations?
#Configuration
#EnableTransactionManagement
public class AppConfig {
#Bean
public DataSource dataSource() {
// What goes here?
}
#Bean
public PlatformTransactionManager txManager() {
// What goes here?
}
}
I've seen a lot of examples with DataSourceTransactionManager and BasicDataSource, but I couldn't find a equivalent annotation driven configuration (that finds the container UserTransaction, etc).
The only way I am aware of is to replicate the behavior of namespace parsers of these custom namespaces.
So, <jee:jndi-lookup> is handled by org.springframework.ejb.config.JndiLookupBeanDefinitionParser and ultimate creates a bean which is an instance of JndiObjectFactoryBean with the passed in attributes.
Similarly, <tx:jta-transaction-manager/> is handled by org.springframework.transaction.config.JtaTransactionManagerBeanDefinitionParser and based on the runtime environment, returns a specific instance of class.
A neat feature of Spring 4 that you can use is #Conditional(reference here). With #Conditional and using a Spring-Boot Conditional implementation called ConditionalOnClass(reference here), you can replicate the behavior of <tx... something like this:
#Configuration
#ConditionalOnClass(name="weblogic.transaction.UserTransaction")
public class WebLogicTxMgrConfig {
#Bean
public JtaTransactionManager txManager() {
return new WebLogicJtaTransactionManager();
}
}
I know this is not a complete answer, but hopefully should help you create the relevant configuration.