I want to use custom JsonSerializer for JSON response of SpringMVC4.
In order to add JsonSerializer, I created WebMvcConfigurerAdapter subclass.
But customization of MappingJackson2HttpMessageConverter didn't work.
Simplify the problem, I tried setJsonPrefix.
But it also didn't work. The response didn't changed.
My code is below. Please tell me what is wrong.
ControllerClass
#Controller
public class SampleController {
#RequestMapping("/sample")
#ResponseBody
public ResponseModel action() {
return new ResponseModel();
}
public static class ResponseModel {
public String id = "001";
public String text = "aaa";
}
}
Configuration
#Configuration
#EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
super.configureMessageConverters(converters);
}
#Bean
protected MappingJackson2HttpMessageConverter converter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setJsonPrefix("prefix");
return converter;
}
}
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
xmlns:aop="http://www.springframework.org/schema/aop">
<!-- base package -->
<context:annotation-config />
<context:component-scan base-package="jp.co.xxx.*" /><!-- my package. contains WebMvcConfiguration class -->
<annotation-driven />
<!-- aop -->
<aop:aspectj-autoproxy />
</beans:beans>
Note.
When server starts, configureMessageConverters method was called.
(Breakpoint confirmation)
I am using AbstractJsonpResponseBodyAdvice subclass for JSONP
(I removed this class, but nothing was changed.)
I used below as reference.
How to configure MappingJacksonHttpMessageConverter while using spring annotation-based configuration?
http://www.baeldung.com/spring-httpmessageconverter-rest
SpringMVC version is 4.1.6
P.S.
In JSONSerializer case is below.
#Configuration
#EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Autowired
protected CustomObjectMapper mapper;
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
super.configureMessageConverters(converters);
}
#Bean
protected MappingJackson2HttpMessageConverter converter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(mapper);
return converter;
}
}
ObjectMapper
#Component
public class CustomObjectMapper extends ObjectMapper {
private static final long serialVersionUID = -6987863269632420904L;
public CustomObjectMapper() {
setSerializationInclusion(Include.NON_NULL);
enable(SerializationFeature.INDENT_OUTPUT);
SimpleModule module = new SimpleModule();
module.addSerializer(DateTime.class, new DateTimeSerializer());
registerModule(module);
}
}
In each case I had no error. But customization didn't work.
In the configureMessageConverters method, if you are not covered and no other converter is added, converters are empty, and WebMvcConfigurationSupport will call addDefaultHttpMessageConverters, which will configure the default converter, which contains the default MappingJackson2HttpMessageConverter.
So adding MappingJackson2HttpMessageConverter in extendMessageConverters will not work.
There are two solutions:
You add the required converter in the configureMessageConverters method itself
To determine the type of converter in extendMessageConverters, set the required properties
sorry,i speek broken english.
I was having this problem as well and discovered this problem, thanks to another site:
#EnableWebMvc is equivalent to in XML based configuration.
If you have BOTH, then the extendMessageConverters doesn't seem to be effective. As soon as I removed the XML entry, bingo.. the custom converters started working.
Related
How can I configure my custom message converter to have register-defaults="false" in a XML-less project with Spring 4?
<mvc:annotation-driven register-defaults="false">
<mvc:message-converters>
<bean class="myproject.MyCustomHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
Currently I have this Configuration:
#Configuration
#EnableWebMvc
#ComponentScan
public class TestDataConfig extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converters.add(converter);
}
}
Thank you
Your Java Configuration as it is, is similar to the one with register-defaults="false" in XML Configuration. You don't need to do anything. But if you want to Register Defaults you would have to extend from WebMvcConfigurationSupport and add the last line specified in the below code snippet.
#Configuration
#EnableWebMvc
#ComponentScan
public class TestDataConfig extends WebMvcConfigurationSupport {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converters.add(converter);
super.addDefaultHttpMessageConverters(); // Have to call this explicitly to register Default Message Converters.
}
}
It is true, what #shazin has written - that Java configuration from the first post is an equivalent to XML's register-defaults="false".
However, if you need to get an equivalent to register-defaults="true" - as far as i'm aware - you could implement extendMessageConverters(List<HttpMessageConverter<?>> converters) method in WebMvcConfigurer (or override it in WebMvcConfigurerAdapter) - like in an example below:
public class TestDataConfig extends WebMvcConfigurerAdapter {
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// your custom implementation
}
}
I am trying to log a method using AOP in Spring. I tried the following code with just System.out.println() but it's not getting called.
Created annotation:
#Retention(value = RetentionPolicy.RUNTIME)
#Target(value = ElementType.METHOD)
public #interface Loggable {
}
Created Aspect
#Aspect
public class MethodLogger {
#Around("execution(* *(..)) && #annotation(Loggable)")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("this is called");
return result;
}
}
Used logging in a method in service layer
#Service("RegionService")
#Transactional(readOnly = false)
public class RegionService implements IRegionService{
#Loggable
#Override
public List<> fetch() {
return dao.xyz();
}
}
Spring configuration
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
>
<context:component-scan base-package="com.sst.tender.spring"/>
<context:annotation-config/>
<context:spring-configured/>
</beans>
Add #Component to MethodLogger class. Also you have to enable AspectJ like one of the following ways:
Adding #EnableAspectJAutoProxy to your configuration bean class. (annotation driven approach)
Adding <aop:aspectj-autoproxy /> to application context file. (XML driven approach)
I have a problem getting EJB beans working when using Spring's java config classes.
Specifically I have the following that works:
#Configuration
#ComponentScan(basePackages = "com.company.web.config")
#ImportResource(value = {"classpath:spring-beans.xml"})
public class AppConfig {
}
#Configuration
#ComponentScan(basePackages = "com.company.web")
public class WebConfig extends WebMvcConfigurationSupport {
// basic Spring MVC setup omitted
}
My spring-beans.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:local-slsb id="fooService" jndi-name="java:app/model/FooServiceBean!com.company.ejb.FooService"
business-interface="com.company.ejb.FooService" />
</beans>
With this configuration, everything works, and I can do this:
#Controller
public class HomeController {
private final FooService fooService;
#Autowired
public MyPageController(FooService fooService){
this.fooService = fooService;
}
// request methods
}
Now i try to get rid of the XML file. According to the documentation the local-slsb should be equivalent
<bean id="fooService"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="java:app/model/FooServiceBean!com.company.ejb.FooService"/>
<property name="businessInterface" value="com.company.ejb.FooService"/>
</bean>
However, if I remove the #ImportResource from AppConfig and put this #Bean method instead, deployment fails because the Controller cannot be instantiated (no autowire candidates found for FooService):
#Bean
public LocalStatelessSessionProxyFactoryBean fooService(){
LocalStatelessSessionProxyFactoryBean factory = new LocalStatelessSessionProxyFactoryBean();
factory.setBusinessInterface(FooService.class);
factory.setJndiName("java:app/model/FooServiceBean!com.company.ejb.FooService");
return factory;
}
Any ideas why this doesn't work? I am using Spring version 4.0.2.
It seems that the issue was related to the order in which configuration was read, and possibly double configuration loading.
Specifically, introducing a separate configuration class and importing it before WebConfig seems to do the trick, like so:
#Configuration
#Import({EJBConfig.class, WebConfig.class})
public class AppConfig {
}
#Configuration
public class EJBConfig {
#Bean
public LocalStatelessSessionProxyFactoryBean fooService(){
LocalStatelessSessionProxyFactoryBean factory = new LocalStatelessSessionProxyFactoryBean();
factory.setBusinessInterface(FooService.class);
factory.setJndiName("java:app/model/FooServiceBean!com.company.ejb.FooService");
return factory;
}
}
#Configuration
#ComponentScan(basePackages = "com.company.web")
public class WebConfig extends WebMvcConfigurationSupport {
// basic Spring MVC setup omitted
}
My Aspect class will be ,
#Configuration
#EnableAspectJAutoProxy
#Component
#Aspect
public class AspectClass {
#Before("execution(* com.pointel.aop.test1.AopTest.beforeAspect())")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before running the beforeAspect() in the AopTest.java class!");
System.out.println("Hijacked Method name : " + joinPoint.getSignature().getName());
System.out.println("************************");
}
}
My other java Class
public class AopTest {
public void beforeAspect() {
System.out.println("This is beforeAspect() !");
}
}
My Main Class is
public class MainMethod {
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext("ApplicationContext/applicationContext.xml");
AopTest test = (AopTest)context.getBean("bean1");
test.beforeAspect();
}
}
My applicationContext.xml is ,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<bean id="bean1" class="com.pointel.aop.test1.AopTest" />
</beans>
In this the #Before("execution(* com.pointel.aop.test1.AopTest.beforeAspect())") in the AspectClass will not be executed before the beforeAspect() in the AopTest , when running Main method.
Good answers are definitely appreciated.
First of all if you're going to use an annotation based configuration, use AnnotationConfigApplicationContext instead of FileSystemXmlApplicationContext. And get rid of the applicationContext.xml file and simply add a #Bean method in your configuration class. Something like this:
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackages = "your.aspect.package")
public class AspectConfig {
#Bean
public AopTest aopTest() {
return new AopTest();
}
}
In your main
public class MainMethod {
public static void main(String[] args) {
AnnotationConfigApplicationContextcontext = new AnnotationConfigApplicationContext(AspectConfig.class);
// don't forget to refresh
context.refresh();
AopTest test = (AopTest)context.getBean("aopTest");
test.beforeAspect();
}
}
In AspectClass you should have #Component, #Aspect, and your method should have the advice or pointcut annotation like #Before. It needs to be a #Component, so that Spring knows to scan it.
Here some code need to add in xml to use annotations-
1.for #component annotation.
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
2.after that use component scan to get all annotated bean class which use #component annotation,and use aop autoproxy-
<context:annotation-config/>
<context:component-scan base-package="mypackage"></context:component-scan>
<aop:aspectj-autoproxy>
</aop:aspectj-autoproxy>
for examples visit-www.technicaltoday.com/p/spring.html
You are missing the point cut definition in your aspect class.
For example;
#Pointcut("execution(* *.advice(..))")
public void logBefore(){}
#Before("logBefore()")
public void beforeAdvicing(){
System.out.println("Listen Up!!!!");
}
You first have to defin the point to weave your aspect to. You do this by using Point cuts.It is the point cut name you give within your #Before annotation. Have a look at my blog post for more information # http://dinukaroshan.blogspot.com/2010/06/aop-with-spring.html
I don't see your AspectClass in the beans configuration. You should also declare it as a Bean.
Is it possible to have the equivalent of <mvc:default-servlet-handler/> defined in an AnnotationConfig(Web)ApplicationContext? Right now I have:
#Configuration
#ImportResource("classpath:/mvc-resources.xml")
class AppConfig {
// Other configuration...
}
with just the following in my resources/mvc-resources.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:default-servlet-handler/>
</beans>
And it works as expected. Is it possible to do this without importing an XML file? It would be a nice way to cut down on some boilerplate.
If you are using Spring 3.1 with WebMvc, you can configure default servlet handling like this:
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
After digging a bit deeper, I found out that this is a known problem and is addressed by annotation features in the upcoming Spring 3.1.
I solved my problem with the following code:
#Configuration
#Import(FeatureConfig.class)
class AppConfig {
...
}
#FeatureConfiguration
class FeatureConfig {
#Feature
public MvcDefaultServletHandler defaultHandler() {
return new MvcDefaultServletHandler();
}
}
This does require using the milestone version of spring, though, but it seems to be the cleanest and preferred way of handling this.
I don't think you can do it out of the box, but you can probably copy what DefaultServletHandlerBeanDefinitionParser does: Create a Bean of type DefaultServletHttpRequestHandler and map it to the URL scheme /**.
I'd say your Bean should subclass DefaultServletHttpRequestHandler and do the mapping in a #PostConstruct method.
#Bean
public DefaultServletHttpRequestHandler defaultServletHttpRequestHandler() {
return new DefaultServletHttpRequestHandler();
}
#Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
Map<String, String> urlMap = new ManagedMap<String, String>();
urlMap.put("/**", defaultServletHandlerName);
SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();
hm.setUrlMap(urlMap);
return hm;
}