ControllerAdvice annotation in spring 4 is not working - spring

In spring-mvc.xml:
<beans ...>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="com.app.controllers.ExceptionController"/>
....
</beans>
In GlobalException.java:
#ControllerAdvice(basePackages = "com.exceptions")
public class GlobalException {
#ExceptionHandler(UserDefinedException.class)
public ModelAndView processCustomException(UserDefinedException ud) {
ModelAndView mav = new ModelAndView("exceptionPage");
mav.addObject("name", ud.getName());
mav.addObject("message", ud.getMessage());
return mav;
}
}
In ExceptionController.java:
public class ExceptionController implements Controller {
#Override
public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
throw new UserDefinedException("Custom Exception has occured", "CustomException");
}
}
Ecxception is throwing as com.exceptions.UserDefinedException: Custom Exception has occured. But ExceptionHandler method is not called. Whats wrong is this code. I'm using spring 4.3 version.

enable Spring's component scanning in your spring-mvc.xml by adding this:
<context:component-scan base-package="com.exceptions" />
and remove your obsolete XML configured Spring bean (<bean class="com.app.controllers.ExceptionController"/>)
also annotate your controller classes with #Controller and add a #RequestMapping to your controller methods, e.g. like this:
#Controller
public class ExceptionController {
#RequestMapping(value="/whatever", method=RequestMethod.GET)
public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
throw new UserDefinedException("Custom Exception has occured", "CustomException");
}
}
this way, your classes annotated with Spring stereotype annotations (#Component, #Service, #Controller, #Repository) should be found, instantiated and registered as Spring beans by Spring itself at application startup!

Related

Spring AOP with bean scanned using mybatis.spring.*.MapperScan

I am working on one component to achieve audit using Spring AOP. I could use it for most of the service's methods. But found that with Mybatis mappers AOP point-cuts don't work.
Basically, Spring AOP only works with Spring-managed beans. But these mapper beans have been scanned using mybatis.spring.*.MapperScan and can be autowired in other Spring components.
Why can these beans not be scanned for Spring AOP? Any idea?
I can use AspectJ but was keen to find out how mybatis.spring.*.MapperScan works.
for example -
I have these configurations one for Mybatis mapper scan and other config for application specific configurations.
#Configuration
#MapperScan("com.test.mapper")
public class ProviderConfiguration {
#Bean
public SqlSessionFactory sqlSessionFactory(final DataSource src) throws Exception {
...
}
}
#Configuration
#EnableAspectJAutoProxy
public class MainConfiguration {
}
My Dao logic where i call mapper method -
#Component
public class TestDao {
//injecting mybatis mapper here
#Inject
private SaveTableData saveTableData;
public TableData save(TableData tableData) {
saveTableData.updateTableData(tableData);
}
}
I have registered my pointcuts as below
#Component
#Aspect
public class TestAdvices {
#Pointcut("execution(* com.test.mapper.SaveTableData.updateTableData(*))")
public void commonSaveTableData(TableData tableData) {
}
#Pointcut("execution(* com.test.service.CreateTableData.createTableData(*))")
public void commonCreateTableData(TableData tableData) {
}
//advices
#After("commonSaveTableData(tableData)")
public void addHistoryWhenSaveTableData(TableData tableData) throws Throwable {
//do stuff
}
//advices
#After("commonCreateTableData(tableData)")
public void addHistoryWhenCreateTableData(TableData tableData) throws Throwable {
//do stuff
}
}
Issue is commonCreateTableData which is on service method works as expected. But commonSaveTableData which is on Mybatis mapper method does't get invoke.
Question is if i can autowire these Mappers in any Spring bean why can't Spring AOP intercept method call using these pointcuts?
I think your pointcut expression is not correct, try this
#Component
#Aspect
public class TestAdvices {
#Pointcut("execution(* com.test.mapper.SaveTableData.updateTableData(*)) && args(tableData)", argNames="tableData")
public void commonSaveTableData(TableData tableData) {
}
//advices
#After("commonSaveTableData(tableData)", argNames="tableData")
public void addHistoryWhenSaveTableData(TableData tableData) throws Throwable {
//do stuff
}
//...
}
The reason you can't cut into the mapper like this is that when mapper is scanned by mybatis, it's bean definition has bean changed in a way that its interface is still the mapper interface but its class has been changed to MapperFactoryBean

Spring AuthenticationSuccessHandler autowired Service/DAO is null

I am having a AuthenticationSuccessHandler which should hold a UserService. My problem is that i am getting a NullPointerException on the userService at this line:
logger.debug(userService.getAllUsers().toString());
AuthenticationSuccessHandlerImpl:
#Repository
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationSuccessHandlerImpl.class);
#Autowired
private UserService userService;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
logger.debug(userService.getAllUsers().toString());
response.setStatus(HttpServletResponse.SC_OK);
response.sendRedirect("index");
}
}
I Have also tried #Service and #Component Annotation but the same error.
It works in all other Services and Controller from my project but not in this Handler.
I also have this line of code in my config:
<context:component-scan base-package="com.net4you.*" />
<tx:annotation-driven />
EDIT:
AuthenticationSuccessHandlerImpl is not created with new, but with:
<security:form-login login-page="/login" default-target-url="/index" authentication-failure-url="/fail2login"
authentication-success-handler-ref="customAuthenticationSuccessHandler"/>
<beans:bean id="customAuthenticationSuccessHandler" class="com.net4you.slamanagement.helper.AuthenticationSuccessHandlerImpl"/>
Project structure:
Debugger:
1) you dont need .*
<context:component-scan base-package="com.net4you.*" />
this is enough
<context:component-scan base-package="com.net4you" />
2) are you sure that userService is null?
3) configuration looks fine, maybe getAllUsers() method is returning null,
can you show its implementation?
UPDATE
You can solve this problem in two ways
1) remove
<beans:bean id="customAuthenticationSuccessHandler" class="com.net4you.slamanagement.helper.AuthenticationSuccessHandlerImpl"/>
and annotate AuthenticationSuccessHandlerImpl like this
#Component("customAuthenticationSuccessHandler")
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationSuccessHandlerImpl.class);
#Autowired
private UserService userService;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
logger.debug(userService.getAllUsers().toString());
response.setStatus(HttpServletResponse.SC_OK);
response.sendRedirect("index");
}
}
2) the second way would be creating setter of userservice in AuthenticationSuccessHandlerImpl , create userservice bean in xml manually and then inject it directly using setter property of authenticationSuccessHandlerImpl in xml, this solution is more complicated and i would suggest you to use first one
Your implementation doesn't work because you define a bean in xml without setting the userservice for it (#autowired doesn't work if you define bean manually) and then you inject this bean into form-login

Not able to get ArgumentResolver working in spring

I am using Spring 4.2.0.RELEASE and trying to use WebArgumentResolver but not able to understand the behavior for my case. There are two custom annotations that I have provided.
My controller has following mapping:
#RequestMapping
public ModelAndView install(#AppFromId final App app, #JsonBody final Map postBody)
MyArgumentResolver:
public class MyArgumentResolver implements WebArgumentResolver {
private static final Logger logger = LoggerFactory.getLogger(AppArgumentResolver.class);
#Override
public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest nativeWebRequest) throws Exception {
String methodName = methodParameter.getMethod().getName();
int parameterIndex = methodParameter.getParameterIndex();
logger.info("Method-name: {}, parameter-index: {}, methodParamClass: {}", methodName, parameterIndex, methodParameter.getParameterType().getSimpleName());
for (Annotation annotation : annotations) {
logger.info("Resolving annotation: {}", annotation.annotationType().getSimpleName());
}
return UNRESOLVED;
}
}
Following is getting logged by MyArgumentResolver when I invoke the controller method:
Method-name: installApp, parameter-index: 0, methodParamClass: App
Resolving annotation: AppFromId
context.xml file
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="../MyArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
My question is, why the second parameter (#JsonBoyd final Map postBody) of the controller-method is not getting resolved/checked by MyArgumentResolver?

#Transactional AspectJ Advice

I added my custom #Around advice to bean's method. Bean is transactional. How can I make by advice to run within the transaction?
I use AspectJ to add advices.
Advice code:
#Aspect
#Order(200)
public class MyAdvice {
#Around
public Object wrap(final ProceedingJoinPoint pjp) throws Throwable {
Object ret = pjp.proceed();
// some processing that requires a transaction
return ret;
}
}
Bean code:
public class MyBean {
// method is wrapped by MyAdvice.wrap
#Transactional
public Object someBusinessMethod() {
// ...
}
}
Spring configuration:
<tx:annotation-driven transaction-manager="transactionManager" order="100" mode="proxy" />
<aop:aspectj-autoproxy />
I need the MyAdvice.wrap to run within the same transaction as MyBean.someBusinessMethod.

Why Spring's #Component does not work on a JSP Custom Tag class?

I have a custom tag:
#Component
public class CVTag extends SimpleTagSupport {
#Inject
private JaxbSupport jaxbSupport;
#Override
public void doTag() throws JspException, IOException {
JspWriter writer = getJspContext().getOut();
Groups groups = jaxbSupport.getJaxbGroups();
}
NullPointerException is thrown as jaxbSupport is null.
Is there really a limitation stipulating Custom-Tag cannot be a Spring managed Bean? or I am doing something wrong?
Using Spring 3.2.4.
Thanks.

Resources