How to catch Exception like in a FrontController in Spring - spring

Basically every repository method can possibly throw a DataAccessException . A lot of exceptions inherit from DataAccessException. So maybe I will catch DuplicateKeyException or maybe DataIntegrityViolationException . But all the other say 40 - 50 exceptions I will not catch explicitly. Instead I will just catch DataAccessException . So why always catch DataAccessException ?? Instead I would prefer catching it just once. But how to do that in Spring. There is no Front Controller. There are just Controllers. So how should I catch it in a central place. The only place I know whould be start of Spring. But I don't think that works.
#SpringBootApplication
#EnableJpaRepositories
public class Application {
public static void main(String[] args) {
try{
SpringApplication.run(Application.class, args);
}
catch(DataAccessException e)
{
//Do your error handling here
}
}
}

You should catch the exceptions at the beans or controllers that has the code managing db access, you can catch and manage this each controller bu the better approach is to implement an exception handler as th guid is showing here https://www.baeldung.com/exception-handling-for-rest-with-spring

Simplified process:
The run method call starts an embadded web server (and the whole spring infrastructure). So actually for example if you try to print out something after run call, it would not appear on the console.
The webserver runs and dispatch your requests in different threads. So the exception will happen on that threads. Spring use lot of exception handlers etc in the background.
So it more complicated in the reality. But you may see that this is not a simple, single threaded application.
The previous answer shows how to handle the exceptions in central place. For simple mvc application, I suggest to use #ControllerAdvice

To catch the exceptions in one central place you can use a common class annotated with ControllerAdvice. Below is a snippet for reference,
#ControllerAdvice
public class CustomizedExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(DataAccessException .class)
public final ResponseEntity<ErrorDetails> externalIdmException(DataAccessException ex,
WebRequest request) {
// exception handling
}
}
This Class will catch exceptions of type to which it is defined in a central place. If you want more specific exceptions to be handled at the class level, #ExceptionHandler method can be preferred.

Related

Spring Cloud Stream Dispatcher has no subscribers

Spring Cloud Stream Dispatcher has no subscribers Error.
After a successful spring boot container start up we need to put few notification messages on a Kafka topic and several of our microservices does same function and for this reason we wrote a common jar that contains out put channel definitions and dispatch utils. And the functionality works as expected as long as we invoke the util right after the SpringApplication.run call.
Following is one of our microservices Application class sample.
#SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class, args);
context.getBean(SchedulerConsumerUtils.class).registerOrRestartConsumerJobs();
}
}
The above set up works as expected, however this puts unnecessary burden the developer to write the boiler template code on every microservice. So to avoid this, we wrote an Aspect implementation to do the same function, however with our aspect approach we are running into the following error.
org.springframework.context.ApplicationContextException: Failed to start bean 'outputBindingLifecycle'; nested exception is org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'schedulertestsvcs:dev:1180.scheduledJobExecutionResponseOutput'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
We tried several approaches like Spring SmartLifeCycle to get a handle on all Kafka Output/Input channel startup completion but all of them are running into the same error.
Following is our Aspect implementation on org.springframework.boot.SpringApplication.run(..)
#Aspect
#Component
public class SchedulerConsumerAspect {
#Autowired
protected ApplicationContext applicationContext;
#AfterReturning(value = "execution(* org.springframework.boot.SpringApplication.run(..))",returning = "result")
public void afterConsumerApplicationStartup(JoinPoint pjp, Object result) throws Throwable {
if(result!=null){
ConfigurableApplicationContext context=(ConfigurableApplicationContext) result;
if(context.containsBean("schedulerConsumerUtils")){
//For what ever reason the following call resulting in Dispatcher has no subscribers for channel error.
//TODO fix the above issue and enable the following call.
context.getBean(SchedulerConsumerUtils.class).registerOrRestartConsumerJobs();
}
}
}
}
During our debug sessions, we found out org.springframework.boot.SpringApplication.run(..) Aspect was called several times during the bootstrap process. First when the aspect was called we got result value as null, after some time spring boot calls the same aspect this time result is not null. Even after getting result not null there is no grantee the component is completely initialized that's why you see a check for context.containsBean("schedulerConsumerUtils"). However after the bean initialization we are seeing output channels are not completely bound.
What is the best way to get handle on Spring Cloud Stream Kafka output/input channel binding completion ?
Why the component invocation works fine in SpringBoot Application but not through Aspect? I struggled on this few days couldn't find the right solution. Any help greatly appreciated.
I followed the suggestion from this post Spring cloud stream - send message after application initalization and used the 3rd option ApplicationRunner. The first two options didn't work for me.
#Component
public class AppStartup implements ApplicationRunner {
#Autowired
protected ApplicationContext applicationContext;
#Override
public void run(ApplicationArguments args) throws Exception {
if(applicationContext!=null){
applicationContext.getBean(SchedulerConsumerUtils.class).registerOrRestartConsumerJobs();
}
}
}

Spring MVC handling exceptions

I've built a spring mvc application using the controller->service->dao architecture. The DAO objects are using hibernate. The services are annotated #Transactional.
I'm trying to catch dao exceptions in the service, wrap them up and then throw them to my controller:
Service
#Override
public Entity createEntity(Entity ent) throws ServiceException {
try {
return entityDAO.createEntity(ent);
} catch (DataAccessException dae) {
LOG.error("Unable to create entity", dae);
throw new ServiceException("We were unable to create the entity for the moment. Please try again later.", dae);
}
}
Controller
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String createEntity(#ModelAttribute(value = "newEntity") Entity newEntity, RedirectAttributes redirectAttributes) {
try {
entityService.createEntity(newEntity);
} catch (ServiceException se) {
redirectAttributes.addFlashAttribute("error", se.getMessage());
}
}
return "redirect:/entity/manage";
}
However, even though the DataAccessException is caught at the service level, it keeps bubbling up to my controller somehow.
If for example I don't meet a unique field criteria on the database level I get an HTTP Error 500 with the following:
org.hibernate.AssertionFailure: null id in com.garmin.pto.domain.Entity entry (don't flush the Session after an exception occurs)
Code is caching DataAccessException not HibernateException, try caching HibernateException
Is there a way to translate HibernateException to something else, then DataAccessException in sping
If you want to handle the exception in the Controller, don't catch it in the Service.
Service
#Override
public Entity createEntity(Entity ent) throws DataAccessException {
return entityDAO.createEntity(ent);
}
Controller
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String createEntity(#ModelAttribute(value = "newEntity") Entity newEntity, RedirectAttributes redirectAttributes) {
try {
entityService.createEntity(newEntity);
} catch (DataAccessException e) {
redirectAttributes.addFlashAttribute("error", e.getMessage());
}
return "redirect:/entity/manage";
}
Or if you want to leverage Spring the handle the exception, use ExceptionHandler annotation. You can find good tutorial online, for example, Spring MVC #ExceptionHandler Example.
To make exception translation working
You have to annotate your DAO with #Repository
Make sure you have declared this bean <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
Here is a beautiful post on different ways to handle exceptions on a Spring MVC project.
Among those, I find using #ControllerAdvice classes, to handle all the exceptions at one place globally, the most convenient in general. Spring Lemon's source code could serve as a good concrete example.

Spring transaction: requires_new beharivour

May be I am misunderstand Spring Requires_new behavior. Here is my code:
#Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRED)
public void outterMethod() throws Exception{
innerMethod1();
innerMethod2();
}
#Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRES_NEW)
public void innerMethod1() throws Exception{
testService.insert(new Testbo("test-2", new Date()));
}
#Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRES_NEW)
public void innerMethod2() throws Exception{
testService.insert(new Testbo("test-2", new Date()));
throw new Exception();
}
When the innnerMethod2 throws Exception, I thought that innerMethod1 still able to commit. But the all the outer and inner transactions rollback. What am I wrong here? How can I do to commit innerMethod1 when innerMethod2 rollback?
Although you have correctly understood the behavior of Propagation.REQUIRES_NEW, you have stumbled upon a common misconception about Spring 's Transactional behavior.
In order for the transactional semantics to be applied (that is for the annotation of the method to have any effect), the method needs to be called from outside the class. Calling a method annotated with transactional from inside the class has absolutely no effect on the transactional processing (because the Spring generated proxy class that contains the transactional code does not come into play).
In your example innerMethod2 maybe annotated with #Transactional but since it is called from outterMethod, the annotation is not being processed.
Check out this part of the Spring documentation

How can I bypass Grails exception handling, in order to use Spring Oauth2?

I am trying to port an Oauth2 client based on Oauth for Spring Security from plain Java/Spring to Grails, and have run into a problem. The crux of the issue appears to be the fact that the design of the Spring Oauth client implementation relies on the assumption that an exception thrown from the Oauth2RestTemplate will be caught in a catch block of the OAuth2ClientContextFilter, thus allowing the filter to issue a redirect response (to send an authorization request to the oath provider).
This works fine in plain Java/Spring but in Grails, the GrailsDispatcherServlet is configured to handle all exceptions via HandlerExceptionResolvers. Thus the exception thrown in the Oauth2RestTemplate (invoked inside a Grails controller) is caught by the GrailsExceptionResolver and is never seen by the OAuth2ClientContextFilter, thus defeating the desired redirect behavior.
All discussions I have found of customizing Grails exception handling all seem to assume that the purpose of the customization is to map the exception to an HTTP error code or to a error page view. But is there some way to tell Grails to simply allow a particular exception to flow through unhandled, so that it can be caught by the servlet filter? Or is it possible to insert a custom HandlerExceptionResolver that re-throws the exception rather than returning a ModelAndView (as is the standard expectation for a HandlerExceptionResolver)? Or is there some other better way to get the Oauth for Spring Security client working inside Grails?
Here's what I eventually came up with. Not sure if it is the best solution but it seems to work:
Create a new MyDispatcherServlet.groovy:
package org.example.com
import org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.web.servlet.ModelAndView
import org.springframework.security.oauth2.client.UserRedirectRequiredException
class MyDispatcherServlet extends GrailsDispatcherServlet {
#Override
protected ModelAndView processHandlerException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {
def e = ex
while (e) {
if (e instanceof UserRedirectRequiredException) {
throw ex
}
e = e.cause
}
return super.processHandlerException(request, response, handler, ex)
}
}
Run grails install-templates and modify the web.xml to use MyDispatcherServlet instead of the default GrailsDispatcherServlet
The result is that MyDispatcherServlet will re-throw an exception that contains a UserRedirectRequiredException so that it can be caught by the OAuth2ClientContextFilter, but other exceptions will be passed on and handled as before by the GrailsExceptionResolver.
I think you can declare exceptionHandler in resources.groovy by defining your custom exception resolver. This custom exception resolver can (optionally) override GrailsExceptionResolver
exceptionHandler(MyExceptionResolver) {
exceptionMappings = ['java.lang.Exception': '/error']
}
class MyExceptionResolver extends GrailsExceptionResolver {
#Override
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
//your custom code
return super.resolveException(request, response, handler, ex)
}
}

EasyMock object for unit testing involving scope="request" bean

I am trying to add some Unit Testing to some of our companies code. Yes, I know it should already be there, but not everyone seems to have the same view of unit testing that I do.
However, I have come against a bit of a stopper for me. Admittedly, my Java, Spring and Unit Testing knowledge are not all that they should be. My problem is this though:
I have added a unit test to my code, which tests a class. This class includes a bean which has scope="request", and when it tries to instantiate the bean it throws an exception:
java.lang.IllegalStateException: No Scope registered for scope 'request'
I believe this is because I don't have a HttpServletRequest object, but I don't know how to create a mock one of these and also I don't know how, once created, to add this Mock Object to the unit test so that it resolves this problem.
Below is a cut down version of the code involved, which I believe includes all of the details that are part of this problem.
How can I get this to work?
#Test
public void handleRequest() {
try {
Message<?> outMessage = (Message<?>) response.handleRequest(map);
} catch (Exception e) {
assertNotNull(e);
}
outMessage.getPayload().toString());
}
public class upddResponse extends AbstractResponseTransform {
#SuppressWarnings("unchecked")
public Message<?> handleRequest(Map<String, Message<?>> messages) throws Exception {
super.addEnvironmentDetails(serviceResponseDocument.getServiceResponse());
}
public abstract class AbstractResponseTransform implements ResponseTransform,
ApplicationContextAware {
private ApplicationContext applicationContext;
private MCSResponseAggregator mcsResponseAggregator;
public ServiceResponseType addEnvironmentDetails(ServiceResponseType serviceResponse) throws Exception {
try {
mcsResponseAggregator = (MCSResponseAggregator) applicationContext
.getBean("mcsResponseAggregator");
}
catch (Exception ex) {
}
}
}
public interface ResponseTransform extends Transform {
public Message<?> handleRequest(Map<String, Message<?>> messages)
throws Exception;
}
<bean id="mcsResponseAggregator" class="com.company.aggregator.MCSResponseAggregator" scope="request" />
You need a WebApplicationContext to handle beans with: scope="request"
I recommend to use stub objects with Spring integration tests and use EasyMock without Spring when you test a class isolated.
You can use mocks within the Spring Context:
but that will not solve your problem as it will not make Spring understand scope="request". You can create your own implementation of the request scope, but I'm getting the feeling that you're better off not going through all this trouble.
The easy way out would be to override your request scoped bean in a little test context. You're technically not testing the original context then, but you will be done a lot quicker.
Spring 3.2 comes with support for this. See "Spring MVC Test Framework"

Resources