Spring-Boot: Trying to throw a custom RunTimeException from #PostConstruct method fails - java

Basically, the code I have is here below. Take into account that this is a "test" state of the code. The original problematic was a call on init() to a different class that threw a checked exception. This throw was catched by a try/catch block, then the application failed when trying to create the exception. All that has been removed for clarity's sake, as the problem was in the "MyCustomRuntimeException" creation.
#Component
public class ClassName {
public ClassName() {
//minor, non problematic operations.
}
#PostConstruct
public void init() {
throw new MyCustomRuntimeException("AAAAAAAH");
}
}
MyCustomRuntimeException is defined like this:
public class MyCustomRuntimeException extends RuntimeException {
public MyCustomRuntimeException (String message) {
super(message);
}
}
And, I'm getting an "UnsatisfiedDependencyException" when creating a class that uses this class. The console points towards the line where the new MyCustomRuntimeException is being thrown, and I don't really get what's going on.
Also, "MyCustomRuntimeException" started as a regular exception, but I saw that I should throw a RunTimeException instead because the #PostConstruct forbids checked exceptions to be thrown. And I've also tried to throw a standard RunTimeException with no luck.
So, I'm clueless here. Any ideas on why I can't throw this exception?

Every bean in the context needs to be correctly created. When an error occurs the creation of beans will stop/fail and the context (or in other words your Application) will not start.
You get an UnsatisfiedDependencyException due to the fact that the ClassName bean is created because it is needed by the other bean. After construction of ClassName it will call the #PostConstruct of the ClassName bean, and that fails due to an exception. Hence the instance doesn't get created, hence an UnsatisfiedDependencyException.
The root cause of the UnsatisfiedDependencyException will be the exception thrown by your own initializer method.

Related

Catching Exception in API to handle all possible exceptions occuring in implementation?

Let say I have 2 projects A (API), and B (implementation).
My sonar-lint tells me I should never throw Exception because it is too generic. So, what should be the proper way to handle any kinds of exceptions in the API, including both runtime and "checked" exceptions ?
Project A
public interface IBuilder {
public void create() throws Exception;
}
Project B
public abstract class ABuilder implements IBuilder {
public void create() throws Exception {
throw myImplException();
}
}
public class ARealBuilder extends ABuilder {
public void create() throws Exception {
//Some Exceptions and RunTimeExceptions can occurs
}
}
If I create my own exception type like this:
public class myException extends Exception {
}
Does this handle RuntimeExceptions ?
Just my two cents, but as I started typing it in a comment it became too long:
Throwing Exception doesn't provide any useful information, what do you do in the catch part of your API method? You always have to handle all exceptions and/or re-throw them.
The proper way of handling exceptions has to be done in the implementation part (Project B):
Is the information not useful or can/should be handled Project B? Handle it (via a retry mechanism or providing a meaningful default value, e.g. user not found in session => return an UnknownUser object or null).
Is the information useful for Project A? Define a project specific exception, e.g. UserNotFoundException and throw that one. Then Project A can handle that specific case.
You don't need to define the RuntimeExceptions as they are bubbling up the call stack until Project A anyway (if not handled/catched before in Project B), but yes they are also children of Exception.

Effects of Try/Catch against Throwing Exceptions in a constructing class' constructor

I was playing around with some of my code and came across something I didn't fully understand. I have a class called SentimentClassifier, the constructor of which looks like this:
public SentimentClassifier(final int nGramToBeUsed) {
try {
classifier = (DynamicLMClassifier<?>) AbstractExternalizable.readObject(new File(etc));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I have another class which creates this one, like so:
public TwitterManager(final int nGramToBeUsed) {
sentimentClassifier = new SentimentClassifier(nGramToBeUsed);
}
If I run the code like this, everything works fine. But if I change the first class from using try/catch to throw the exception, like so:
public SentimentClassifier(final int nGramToBeUsed) throws ClassNotFoundException, IOException {
classifier = (DynamicLMClassifier<?>) AbstractExternalizable.readObject(new File(etc));
}
Suddenly the second class complains that the IOException isn't being handled. Why is this thrown only for the thrown exception and not for the try/catch?
When you call a method M1 from another method M2:
If some code in M1 raises some Checked Exception, and the method M1 itself handles it, rather than throwing it, you don't have to worry about the exception while calling it.
Now, if the exception raised in M1, is not being handled in M1 itself, rather it is propagated up the stack trace, then M1 must declare that exception in the throws clause. This is just for the convenience of the calling method to know that it should be ready to handle those exception in case they are thrown. This is only the case with Checked Exception.
But if the calling method M2, doesn't handle that exception, it has the option to re-declare that exception to be thrown in it's own throws clause, in which case the exception will be propagated further up the stack trace.
If method M2 does neither of the previous two task, you will get a compiler error. Because you haven't given any proper path or way to handle the exception that can be thrown.
Note all the above arguments are true for Checked Exception only. For Unchecked exception, you don't need to handle it yourself, neither you need to declare it in throws clause.
Suggested Read:
Java: checked vs unchecked exception explanation
Unchecked Exception controversies
JLS - The Kinds and Causes of Exceptions
In Java, if a method declares that throws an Exception (other than RuntimeException), callers must handle the exception. They can do this one of two ways: catch it, or declare that they themselves throw it.
You moved the handling of these two exceptions from the SentimentClassifier constructor to its callers.
If the constructor declares any exceptions, the calling code must handle them or declare them. After all, the constructor could throw/propagate these exceptions, and any code that calls it must handle them.
When you catch an exception, it means that you will deal with it on the catch block, and its consequences, so the external code can continue to progress without being warned about the internal exception.
If your exception is thrown, you are forcing by contract to any creator/invoker class to deal with any declared exception that could be produced during the initialization/execution process, as it can be critical for the business logic.
In this case, if the exceptions that can be generated during init are critical, and could stop the class from working properly, they should be thrown, as the creator class TwitterManager could have a disfuncional or partially initialized instance of the SentinelClassifier object, leading to unexpected errors.

Record instantiation of java.lang.Throwable transparently [duplicate]

How can I detect when an Exception has been thrown anywhere in my application?
I'm try to auto-magically send myself an email whenever an exception is thrown anywhere in my Java Desktop Application. I figure this way I can be more proactive.
I know I could just explicitly log and notify myself whenever an exception occurs, but I'd have to do it everywhere and I might(more likely will) miss a couple.
Any suggestions?
You probobly don't want to mail on any exception. There are lots of code in the JDK that actaully depend on exceptions to work normally. What I presume you are more inerested in are uncaught exceptions. If you are catching the exceptions you should handle notifications there.
In a desktop app there are two places to worry about this, in the event-dispatch-thread (EDT) and outside of the EDT. Globaly you can register a class implementing java.util.Thread.UncaughtExceptionHandler and register it via java.util.Thread.setDefaultUncaughtExceptionHandler. This will get called if an exception winds down to the bottom of the stack and the thread hasn't had a handler set on the current thread instance on the thread or the ThreadGroup.
The EDT has a different hook for handling exceptions. A system property 'sun.awt.exception.handler' needs to be registerd with the Fully Qualified Class Name of a class with a zero argument constructor. This class needs an instance method handle(Throwable) that does your work. The return type doesn't matter, and since a new instance is created every time, don't count on keeping state.
So if you don't care what thread the exception occurred in a sample may look like this:
class ExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
handle(e);
}
public void handle(Throwable throwable) {
try {
// insert your e-mail code here
} catch (Throwable t) {
// don't let the exception get thrown out, will cause infinite looping!
}
}
public static void registerExceptionHandler() {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName());
}
}
Add this class into some random package, and then call the registerExceptionHandler method and you should be ready to go.
The new debugging hooks in Java 1.5 let you do this. It enables e.g. "break on any exception" in debuggers.
Here's the specific Javadoc you need.
Check out Thread.UncaughtExceptionHandler. You can set it per thread or a default one for the entire VM.
This would at least help you catch the ones you miss.
If you're using a web framework such as Spring then you can delegate in your web.xml to a page and then use the controller to send the email. For example:
In web.xml:
<error-page>
<error-code>500</error-code>
<location>/error/500.htm</location>
</error-page>
Then define /error/500.htm as a controller. You can access the exception from the parameter javax.servlet.error.exception:
Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
If you're just running a regular Java program, then I would imagine you're stuck with public static void main(String[] args) { try { ... } catch (Exception e) {} }
If you are using java 1.3/1.4, Thread.UncaughtExceptionHandler is not available.
In this case you can use a solution based on AOP to trigger some code when an exception is thrown. Spring and/or aspectJ might be helpful.
In my current project I faced the similar requirement regarding the errors detection. For this purpose I have applied the following approach: I use log4j for logging across my app, and everywhere, where the exception is caught I do the standard thing: log.error("Error's description goes here", e);, where e is the Exception being thrown (see log4j documentation for details regarding the initialization of the "log").
In order to detect the error, I use my own Appender, which extends the log4j AppenderSkeleton class:
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class ErrorsDetectingAppender extends AppenderSkeleton {
private static boolean errorsOccured = false;
public static boolean errorsOccured() {
return errorsOccured;
}
public ErrorsDetectingAppender() {
super();
}
#Override
public void close() {
// TODO Auto-generated method stub
}
#Override
public boolean requiresLayout() {
return false;
}
#Override
protected void append(LoggingEvent event) {
if (event.getLevel().toString().toLowerCase().equals("error")) {
System.out.println("-----------------Errors detected");
this.errorsOccured = true;
}
}
}
The log4j configuration file has to just contain a definition of the new appender and its attachement to the selected logger (root in my case):
log4j.rootLogger = OTHER_APPENDERS, ED
log4j.appender.ED=com.your.package.ErrorsDetectingAppender
You can either call the errorsOccured() method of the ErrorsDetectingAppender at some significant point in your programs's execution flow or react immidiately by adding functionality to the if block in the append() method. This approach is consistent with the semantics: things that you consider errors and log them as such, are detected. If you will later consider selected errors not so important, you just change the logging level to log.warn() and report will not be sent.
In this case I think your best bet might be to write a custom classloader to handle all classloading in your application, and whenever an exception class is requested you return a class that wraps the requested exception class. This wrapper calls through to the wrapped exception but also logs the exception event.
I assume you don't mean any Exception but rather any uncaught Exception.
If this is the case this article on the Sun Website has some ideas. You need to wrap your top level method in a try-catch block and also do some extra work to handle other Threads.
Sending an email may not be possible if you are getting a runtime exception like OutOfMemoryError or StackOverflow. Most likely you will have to spawn another process and catch any exceptions thrown by it (with the various techniques mentioned above).
There is simply no good reason to be informed of every thrown exception. I guess you are assuming that a thrown exception indicates a "problem" that your "need" to know about. But this is wrong. If an exception is thrown, caught and handled, all is well. The only thing you need to be worried about is an exception that is thrown but not handled (not caught). But you can do that in a try...catch clause yourself.

Testing Exceptions of a method with EasyMock

I am newbie to unit testing. I am using TestNG with MyEclipse to develop unit test cases for my application. While doing it I am facing some problems with EasyMock. Here is my code (Name of the class, method names and return types are changed for security reasons but you will get a clear idea what I am trying to achieve here).
public MyClass
{
// This is a method in my class which calls a collaborator which I
// want to mock in my test case
public SomeObject findSomething(SomeOtherObject param) throws Exception
{
SomeOtherObject param a = myCollaborator.doSomething(param);
// Do something with the object and then return it
return a;
}
}
Now here is my test. Now what I actually want to achieve in my test
case is that I want to check that my function (findSomething) properly
throws exception in case some exception is thrown. In future some
other developer can change the signature (throws Exception isn't
really part of method signature) of the method and remove the throws
Exception from my method. So how can I make sure that nobody changes
it?
#Test(dataProvider="mydataProvider", expectedExceptions=Exception.class)
public void MyTest(SomeOtherObject param) throws Exception {
{
EasyMock.expect(myCollaboratorMock.doSomething(param)).andThrow(new Exception());
EasyMock.replay(myCollaboratorMock);
}
I am getting exception
"java.lang.IllegalArgumentException: last
method called on mock cannot throw java.lang.Exception"
What I am
doing wrong here? Can someone shed some light on how to write a test
case for my particular scenario?
The collaborator's doSomething() method doesn't declare that it may throw Exception, and you're telling its mock to throw one. It's not possible.
Exception is a checked exception. It can only be thrown if it's declared in the method signature. If the method has no throws clause, all it can do is throwing runtime exceptions (i.e. RuntimeException or any descendant class).

#PostConstruct & Checked exceptions

In the #PostConstruct doc it says about the annotated methods:
"The method MUST NOT throw a checked exception."
How would one deal with e.g. an IOException which can be thrown in such a method? Just wrap it in a RuntimeException and let the user worry about the faulty initial state of the object?
Or is #PostConstruct the wrong place to validate and initialize objects which got their dependencies injected?
Yes, wrap it in a runtime exception. Preferebly something more concrete like IllegalStateException.
Note that if the init method fails, normally the application won't start.
Generally, if you want or expect application start-up failure when one of your beans throws an exception you can use Lombok's #SneakyThrows.
It is incredibly useful and succinct when used correctly:
#SneakyThrows
#PostConstruct
public void init() {
// I usually throw a checked exception
}
There's a recent write-up discussing its pros and cons here: Prefer Lombok’s #SneakyThrows to rethrowing checked exceptions as RuntimeExceptions
Enjoy!
Use a softened exception like so, in effect wrapping in RuntimeException:
private static RuntimeException softenException(Exception e) {
return new RuntimeException("Softened exception.", e);
}
Then usage is like:
} catch (IOException e) {
throw softenException(e);
}

Categories

Resources