Java ExceptionHandler whole Class - java

Is there a way to set a ExceptionHandler for a Class and Exceptionclass?
I have a class like this:
public class MyServiceClass {
public void foo() {
//some Code...
throw new MyCustomRuntimeException();
//some more Code...
}
public void foo2() {
//some other Code...
throw new MyCustomRuntimeException();
//more other Code...
}
}
Now I would like to define a MyCustomRuntimeException - Handler something like this:
private void exceptionHandler(MyCustomRuntimeException ex) {
//some Magic
}
Which should be used everytime a MyCustomRuntimeException is thrown in this class. I know I could use try, catch, finally in each method, but is there a Class wide solution? Would like to skip the boilerplate
try {
...
} catch (MyCustomRuntimeException ex) {
exceptionHandler(ex);
}
Iam using Spring in this application (no Spring Boot), but I found nothing how to use #ExceptionHandler for plain Spring. I tried the following (doesn`t work):
EasyApplication
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class EasyApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
FooBar foo = context.getBean(FooBar.class);
foo.doException();
}
}
FooBar
import org.springframework.web.bind.annotation.ExceptionHandler;
public class FooBar {
public void doException() {
throw new RuntimeException();
}
#ExceptionHandler(value = RuntimeException.class)
public void conflict() {
System.out.println("Exception handled!");
}
}
MyConfiguration
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MyConfiguration {
#Bean(name = "FooBar")
public FooBar fooBar() {
return new FooBar();
}
}

If you are not using spring-mvc and not in a multi-threaded environment, you would be able to do well with the following.
public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("This is from the uncaught");
}
}
And then add this line in your main method. This works for small applications, and spring has minimal role here.
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
If you have a bigger application and needs a more elegant solution - look to introduce aspects (AOP) in to your app.
Edited June 2nd 2020
This is when spring-mvc is used
You can use #ExceptionHandler for this. Spring Tutorial
#ExceptionHandler can handle both class specific and global handlers (via #ControllerAdvice)
The class specific handlers is triggered before global handlers. So best practice is to use RuntimeException and Exception in global handlers, instead of using them in individual classes. Reduces boilerplate further.

Related

Adding new AOP Advisor in runtime dynamically with expression coming from rest endpoint in Spring Framework

I am trying to implement capability of addition of new advisors to Spring beans. Idea is I will write Rest endpoint and will get PointCut expression and Bean name which I want to apply expression to via that endpoint. After I get pointcut expression and bean name, I will create new advisor with expression. Then I will add this advisor to proxy of existing bean.(Bean name coming from rest point.)
According to this SO question https://stackoverflow.com/a/49080647 I wrote code below for adding new advisors. In setAdvisor(Class beanClazz, Advisor advisor) method the line of Advised advisedBean = ((Advised) bean); Casting did not work. Probably because of bean instance coming from ApplicationContext is not a proxy so I got CastingException.
Then I tried implement to create my own proxy of the bean and adding Advisor to this proxy again it did not work. This time I could add advisor to proxy but MethodInterceptor did not invoked so aop did not worked. Probably The reason it doesn't work, I did not put newly created proxy into somewhere like ApplicationContext etc. So where should I put this proxy or how can I change Spring to use this proxy instead of real instance of bean in ApplicationContext.
Besides this solution, if you have another solution, I would be very glad.
You can check implementations of classes below.
LoggingAttacher.Java
import org.aopalliance.aop.Advice;
import org.apache.naming.factory.BeanFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class LoggingAttacher implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
static <T> T getBean(Class<T> beanClazz) {
return context.getBean(beanClazz);
}
public static <T> void setAdvisor(Class<T> beanClazz, Advisor advisor) {
try {
T bean = getBean(beanClazz);
Advised advisedBean = ((Advised) bean);
advisedBean.addAdvisor(advisor);
} catch (BeansException e) {
e.printStackTrace();
}
}
public static <T> void setAdvisorWithNewProxy(Class<T> beanClazz, Advisor advisor) {
try {
T bean = getBean(beanClazz);
Advised advisedBean = ((Advised) createProxy(bean));
advisedBean.addAdvisor(advisor);
} catch (BeansException e) {
e.printStackTrace();
}
}
public static <T> Advised createProxy(T bean) {
if (bean instanceof Advised) {
System.out.println("Bean " + bean + " is already an advised proxy, doing nothing");
return (Advised) bean;
}
System.out.println("Creating proxy for bean " + bean);
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(bean);
return (Advised) proxyFactory.getProxy();
}
// Note: MypointCutAdvisor extends DefaultPointcutAdvisor!!!
public static MyPointCutAdvisor createAdvisor(String expression) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expression);
return new MyPointCutAdvisor(pointcut, new LoggingInterceptor());
EnablingAopController.java
#RestController
public class EnablingAopController {
#GetMapping("/enable-aop")
public String enableAop() {
MyPointCutAdvisor myPointCutAdvisor = LoggingAttacher.createAdvisor("execution(* com.argmnt.logging.logging_project.AppService.*(..))");
LoggingAttacher.setAdvisor(AppService.class, myPointCutAdvisor);
return "example1";
}
}
MyPointCutAdvisor.java
import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class MyPointCutAdvisor extends DefaultPointcutAdvisor {
public MyPointCutAdvisor(Pointcut pointcut, Advice advice) {
super(pointcut, advice);
}
}
LoggingInterceptor.java
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LoggingInterceptor implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("in interceptor");
return invocation.proceed();
}
Note: In case you ask I also added #EnableAspectJAutoProxy annotation on the ApplicationMain class.
I also examine https://docs.spring.io/spring-framework/docs/3.0.0.M4/reference/html/ch08s02.html
and found little bit about 8.2.4.2 Dynamic pointcuts but It is very small paragraph I couldn't understand well.
Also found https://stackoverflow.com/a/43052250 this answer for removing and adding beans to ApplicationContext but could not find how to put proxy that I created into ApplicationContext or somewhere

Sharing an instance of a class across a spring boot application

I have a particular class used to interface with a service that requires initialization. In the application lifecycle, the only place this makes sense is in the start of the application because the rest of the spring application cannot run without it. I had the idea to do this:
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
try {
MyRequiredService mrs = new MyRequiredService();
mrs.connect(); // This will throw if it fails
run(MyApplication.class, args);
} catch(MyException e) {
System.out.println("Failed to connect to MyRequiredService!");
}
}
}
This will launch the service and attempt to connect but I have one big problem. How do I pass this class around the application? I need it's functions in the service endpoints I am writing.
I didn't see anything obvious and searching "passing class instance in spring boot application" turns up a bunch of unrelated topics.
Is there a smart, clean way to do this in spring boot? I apologize for a contrived example. The names of the service are unique enough I didn't want to violate any agreements.
You can make Spring do this for you. First, you need to annotate your class with #Service, so Spring will pick it up when scanning for classes.
Then, define an init() method and annotate it with #PostConstruct. Spring will instantiate your MyRequiredService class and call init()
#Service
public class MyRequiredService {
#PostConstruct
public void init() {
connect();
}
public void connect() {
// ...
}
}
You could call connect() from the constructor, but I don't like to define objects that may throw exceptions out of the constructor.
And then, you can use MyRequiredService in some other class by injecting it via the #Autowired annotation:
#Component
public class MyOtherClass {
private final MyRequiredService service;
public MyOtherClass(final MyRequiredService service) {
this.service = service;
}
// Other methods here.
}
This has the same overall effect as what you're trying to do above. If MyRequiredService fails, the application will not start up.
Make it a bean. Then it will be in the ApplicationContext which then you can pass to your desired other classes through the constructor
#Configuration
public class ApplicationConfiguration
{
#Bean
public MyRequiredService myRequiredService()
{
MyRequiredService mrs = new MyRequiredService();
try {
mrs.connect(); // This will throw if it fails
return mrs;
} catch(MyException e) {
log.error("Failed to connect to MyRequiredService!");
throw new IllegalStateException("MyRequiredService failed connection. Stopping startup");
}
}
#Bean
public SomeOtherService someOtherService(MyRequiredService mrs) {
return new SomeOtherService(mrs);
}
}
IMHO Instead of catching the error and logging it. I would throw it and stop the application from starting, but to keep with your example I added the throw IllegalStateException after the log.
Doing it this way Spring will create your MyRequiredService bean in the ApplicationContext then you can see I added as a parameter needed by the bean below that. Spring will grab that bean out of the ApplicationContext and supply it to the bean. If Spring doesn't find the bean in the ApplicationContext it will throw an error and stop the application from startup.
a class implements BeanFactoryPostProcessor which is init before normal bean
#Configuration
public class MyRequiredService implements BeanFactoryPostProcessor,
PriorityOrdered, InitializingBean {
#Override
public int getOrder() {
return Integer.MIN_VALUE;
}
public void connect() {
// ...
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
#Override
public void afterPropertiesSet() throws Exception {
connect();
}
}

Aspect Before annotation not working

Testing out Aspect #Before annotation in a Spring Boot application and it is not working. No Errors thrown. Just simply not working. It is a very simple rest service as below. Been at it for some time now and any tutorials and answers here seems to point that this is correct. My rest service returns correctly. Just that the message from Aspect doesn't print. I am very confident my package structure is correct. Please advice.
#SpringBootApplication
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class StuffApplication {
public static void main(String[] args) {
SpringApplication.run(StuffApplication.class, args);
}
}
#RestController
#RequestMapping("/information")
public class ContentController {
#GetMapping("/person")
public People getPerson(Model model){
log(); // expecting the aspect print to occur when I call this.
// some logic to get personList which works fine
return new People(personList);
}
public void log(){
System.out.println("This is a logger");
}
}
#Aspect
#Component
public class JsonAspect {
#Before(value = "execution(* com.example.stuff.controller.ContentController.log())")
public void printBefore(){
System.out.println("I was called before the logger"); // never prints when I call log method
}
}

#DeclareParents fail to introduce new method

everybody, I am a beginner in Spring and I am encountering some problems with #DeclareParents. I follow the instructions in Spring In Action but I fail to realize the introduction.
Here are my codes.
I first define Interface performance
public interface Performance {
void perform();
}
and then implement the interface.
#Component
public class OnePerformance implements Performance {
#Autowired
public OnePerformance(){
}
public void perform() {
System.out.println("The Band is performing....");
}
}
I want to introduce method void performEncore() into Performance.
So I define the Interface,
public interface Encoreable {
void performEncore();
}
implement it,
#Aspect
public class DefaultEncoreable implements Encoreable{
public void performEncore() {
System.out.println("performEncore");
}
}
and introduce it,
#Aspect
#Component
public class EncoreableIntroduction {
#DeclareParents(value="Performance+",
, defaultImpl=DefaultEncoreable.class)
public static Encoreable encoreable;
}
I use autoconfiguration,
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
public class ConcertConfig {
}
However, when testing, I fail to introduce method void performEncore().
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes= ConcertConfig.class)
public class OnePerformanceTest {
#Autowired
private Performance performance;
#Test
public void perform() throws Exception {
performance.perform();
}}
And I also enabled AspectJ Support Plugins.
I have read the book and several blogs carefully but I still can not find the cause. So what may be the cause of this problem? Thanks in advance.
Thanks for M. Deinum, NewUser and Wim Deblauwe. With their help, I finally figured out the problem. The previous JUnit4 class is not correct.
The proper solution to solve this problem is to cast Performance into Encoreable, and then call the performEncore() method.
The code is as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes= ConcertConfig.class)
public class OnePerformanceTest {
#Autowired
private Performance performance;
#Test
public void perform() throws Exception {
Encoreable encoreable = (Encoreable)(performance);
encoreable.performEncore();
}
}

Is there a way to get Guice to fail fast during Guice.createInjector

My project is using Guice as the IOC container responsible for providing dependencies (service classes) to a large graph of objects (mostly singletons). Sometimes if a dependency fails during construction and this dependency is required by many objects, the failure will occur over and over again adding the exceptions to the Guice ProvisionException.
I can understand the rational for this behaviour as it gives a list of all the errors that occur to save fixing issues piece meal. However, I would like to disable this feature and 'Fail Fast', as the repeated failure in this case is resource intensive. Further more the 'ProvisionException' contains a list of the same exception.
I do appreciate that this behaviour is symptomatic (smells) of bad practice in the implementation (i.e. resource intensive object creation), but since the dependencies are abstractions for which anyone can provide implementations and plugin using dependency injection there is little defence against it.
What I would like to know is:-
Is there a parameter that enables Guice to exit Injector creation at the first exception?
Any help would be greatly appreciated.
Edit:
#Test
public void guiceExample()
{
Injector injector = Guice.createInjector(new TestModule());
try{
IAmANeedyObject instance = injector.getInstance(IAmANeedyObject.class);
}
catch (ProvisionException e)
{
assertThat(e.getErrorMessages().size(),Is.is(2));
}
}
This test assets two exceptions have been thrown
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
public class TestModule extends AbstractModule {
#Override
protected void configure() {
bind(IWasDesignedWithHonestIntent.class).to(NastyThrowingExample.class);
bind(IMindMyOwnBusiness.class).to(SomeLucklessObject.class);
bind(IAlsoMindMyOwnBusiness.class).to(SomeEquallyLucklessObject.class);
bind(IAmANeedyObject.class).to(LowSelfEsteem.class);
}
}
interface IWasDesignedWithHonestIntent {}
interface IMindMyOwnBusiness {}
interface IAlsoMindMyOwnBusiness {}
interface IAmANeedyObject {}
#Singleton
class NastyThrowingExample implements IWasDesignedWithHonestIntent {
#Inject
public NastyThrowingExample() throws LongSlowAgonisingDeathException {
throw new LongSlowAgonisingDeathException("I am dying");
}
}
class LongSlowAgonisingDeathException extends Exception {
#Inject
public LongSlowAgonisingDeathException(String message) {
super(message);
}
}
class SomeLucklessObject implements IMindMyOwnBusiness {
#Inject
public SomeLucklessObject(IWasDesignedWithHonestIntent designedWithHonestIntent) {
}
}
class SomeEquallyLucklessObject implements IAlsoMindMyOwnBusiness {
#Inject
public SomeEquallyLucklessObject(IWasDesignedWithHonestIntent designedWithHonestIntent) {
}
}
class LowSelfEsteem implements IAmANeedyObject {
#Inject
public LowSelfEsteem(IMindMyOwnBusiness iMindMyOwnBusiness, IAlsoMindMyOwnBusiness alsoMindMyOwnBusiness) {
}
}
Is there a parameter that enables Guice to exit Injector creation at the first exception?
I'm afraid that don't, it doesn't.
You will have to continue with a code like your example.
You can always suggest this for the Guice team on their Google Code page.

Categories