AspectJ: How to log the successful completion of a method? - java

So I am working with AspectJ to refactor my program to remove all logging calls from the main classes. Instead, all logging calls will occur via aspects. So far, here's what I've done successfully:
Catching all exceptions. Since I already have my exception handling pretty unified to begin with (Exceptions propagate up call stack until they reach my controller, then get caught), this wasn't too difficult. Using handle(Exception) I've got every catch block tied to an aspect that will log the exception before the catch block executes.
Debug information logging. Basic things like entering a particular method, etc. Again, relatively simple using before() and, sometimes, args() or thisJoinPoint.getArgs() to capture parameters.
The final thing I need to do, though, is properly log successful completion of key methods. Here is a minor example, of a block of code as it currently exists in my program, so I can better explain my meaning here:
private static void loadDefaultProperties(){
defaultProperties = new Properties();
try {
defaultProperties.load(
Main.class.getClassLoader().getResourceAsStream(
"default.properties"));
if(defaultProperties.size() == 0){
throw new IOException();
}
//THE CURRENT LOGGING LINE THAT NEEDS TO BE MOVED TO AN ASPECT
LOGGER.logp(Level.INFO, Main.class.getName(),
"loadDefaultProperties()",
"Default Properties file loaded successfully");
}
catch (IOException ex){
//THIS EXCEPTION IS LOGGED USING HANDLE(EXCEPTION) IN AN ASPECT
displayExceptionDialog(ex);
}
}
So, this method loads the default properties from the classpath. If it fails, an IOException is thrown. However, if an exception is not thrown, and it performs its task successfully, I want to log that as well.
This particular example is a relatively minor item that wouldn't be a huge deal to miss, but this is the style currently used everywhere in the application.
How would I configure a pointcut/advice in AspectJ to only run after this method completes, and recognize that it does so successfully?
PS. I've considered propagating the exception further up the call stack. That would allow me to use a simple after() returning(Object o) advice to accomplish this. If an exception is thrown, this advice will not run because the method won't return properly.
The problem with that is there aren't many levels higher than this in the call stack. This particular method in my example is called directly by my main method immediately following the program's initialization. In my controller class, there's only one level higher in the call stack for all of my methods there as well.
I guess I could do this, but I want to see if there's another option first, rather than pool all of those exceptions together in one place.

You can certainly use a pointcut to wrap anything in the call stack, including main():
public aspect WrapMain
{
pointcut mainMethod() : execution(public static void main(String[]));
before() : mainMethod() {
System.out.println("Starting application...");
}
after() : mainMethod() {
System.out.println("Terminating application...");
}
}
If you are generating aspects using Java, you can use the #AfterReturning and #AfterThrowing annotations to manage successful or exceptional cases.
#Pointcut("execution(your-method-signature-here)
public void yourPointcut(){}
#AfterReturning(pointcut = "yourPointcut()", returning ="returnValue")
public void afterSuccessAdvice(JoinPoint jp, Object returnValue) {
// log here
}
#AfterThrowing(pointcut = "yourPointcut()", returning ="returnValue")
public void afterFailureAdvice(JoinPoint jp, Object returnValue) {
// log here
}
Here's a Javaworld article with examples that explains logging method entry and exit.

Related

Java: Testing if an exception is caught within a larger system

I know there are a number of questions on this topic, but all of them seem to assume one of two things:
You just want to test if an exception was thrown and not caught,
You should test the function that is inside of the try block
directly
I'm not sure how I can apply those options to this case. I have a small try/catch block, like so:
try {
o.getDataContainer().build(...);
o2.setDataContainer(o.getDataContainer());
} catch (final Exception e) {
LOGGER.error("Data set failed", e);
}
As you can see, if o.getDataContainer() returns null, an exception would be triggered. However, that exception is then caught, and the test tool considers it a successful test. Is it possible to test that the exception occurred without changing the code?
I ask because our logging system triggers a trouble ticket if it picks up an exception that is caught and logged. Since it is common human error to forget to guard something like this, I would like to write UTs that can test if an exception was triggered and caught. I can't remove the whole-program protection provided by the catch block, but the error would also cause a degradation of the user experience, since the data isn't being passed along. (I work in a place where minutes of site downtime equal millions of dollars lost.)
In other words: The exception is an error, and we want to log it and investigate it, but in case this manages to trigger on prod, we don't want to risk the whole site going down.
Note: This try/catch sits inside a much larger function with many such try/catch blocks. One could easily argue bad overall design, but fixing it is not an option (without a huge amount of free dev time, at least).
Update: As the task at hand does not allow me to spend a great deal of time on this, I went with a very simple generic test that would fail if the guard and catch were both removed so that I could move on. But, I'm leaving the question unanswered for now in hopes of continuing conversation. I would love to be able to write a simple UT for each new feature that fails if any exceptions are triggered and caught.
Ignoring the issues with this code (Sometimes you've gotta put lipstick on a pig, I guess), this is how I might handle the situation.
I'd use Mockito and mock o2, then use an Answer to ensure the method is invoked.
A test might look like this:
#RunWith(MockitoJUnitRunner.class)
public class TestClass{
#Mock
O2 o2;
#Mock
O1 o1;
boolean exceptionThrown = false;
#Test
public void test(){
Mockito.doAnswer(new Answer<Void>(){
public Void answer(InvocationOnMock invocation) throws Throwable {
exceptionThrown = true;
throw new RuntimeException("some message");
}
}).when(o2).setDataContainer(DataContainer.class);
}
}
Essentially, you can Mock out o2 in your example, and force the exception.
If this doesn't quite do what you want, you may need to mock LOGGER and verify that it's invoked with LOGGER.error("some message");. Unfortunately, mocking statics is not at all elegant, but it can be done with PowerMock.
You could add a custom handler to LOGGER that just throws when an error is logged. For java.util.logging you could do something like:
LOGGER.addHandler(new Handler() {
public void publish(LogRecord record) {
if ("Data set failed".equals(record.getMessage())) {
throw new RuntimeException(record.getThrown());
}
}
public void flush() {}
public void close() throws SecurityException {}
});
I think log4j calls it "Appender," but the same principle should work. See How to create a own Appender in log4j? or How to Create a Custom Appender in log4j2?

Why does Sun prefer NoSuchMethodError + NullPointerException instead of Class inspection?

I did a small debug session and stumbled over the following code snippet in Sun/Oracle's code:
try {
XmlSchema s = null;
s.location();
} catch (NullPointerException e) {
// as epxected
} catch (NoSuchMethodError e) {
// this is not a 2.1 API. Where is it being loaded from?
...
}
I think this has several flaws by first of all expecting a NullPointerException, using ((XmlSchema)null).location(); and expecting a NoSuchMethodError. If I would do the code review I would flag this as unappropriated code by triggering an exception as a regular event.
In my opinion using XmlSchema.getClass().getMethod("location", new Object[0]) would be a some what better idea.
Since this code is used in the official API implementation I wonder if there are edge cases, I am not aware of which prevent class inspection being a good solution and one has to use this code snippet as a fall back.
UPDATE:
This question is related to "Strange NullPointerException CATCH in OpenJDK JAXB but it is not answering my question about the why do they do it. It is just an explaination what it does not about why they do it.
UPDATE2:
Using the test code:
#Test
public void test() throws NoSuchMethodException, SecurityException {
Method method = ArrayList.class.getMethod("size");
if(method == null)
throw new UnsupportedOperationException();
}
and
#Test
#SuppressWarnings("null")
public void test2() {
ArrayList<?> list = null;
try {
list.size();
}
catch(NullPointerException e) {
}
catch(NoSuchMethodError e) {
throw new UnsupportedOperationException();
}
}
I found that TestNG reports 0s for both tests (after you warm up). Since the code is executed within a static method of a class this code is executed at most once.
So the timing is not the reason. Another problem is that a modern compiler detects the attempt to execute the location method on a null reference and therefore one need to suppress the execution.
So the timing is not the reason (anymore?) for preferring this hack instead of a proper class inspection.
Does anyone know more answers to this?
If you use a catch for handling the NoSuchMethodError, the slow code is used exceptionally. If instead you use reflection for checking the existence of the method, then the slow code is always used.
It appears that the code fragment is now referred to as old legacy code that was never maintained in the meantime. Especially if one notice that any modern IDE flags this code snippet as a accessing a NULL reference.
The reason for using this might have been the problems with reflections (slow) 15 years ago but at least today do not make sense anymore.
Also generating a NullPointerException everytime within the normal application flow and therefore generate such an important exception and unnecessarily interfere with a debug session this can be considered a defect.
So final conlusion: Do not use this code snippet to verify a compatible class version, use reflection instead.

Correctly setting up Java exception handling

I've been attempting to write Java exception handlers for a while now, have tried multiple methods and have even visited/read through Oracle's "The Java Tutorials" and I still cannot get it straight. I'm unsure what I am doing wrong. I have a given class (TooLowException) for the exception that I am trying to use. In the method I am attempting to use it in I am using an argument that I need to catch if it is less than zero.
public int func(int num) throws TooLowException {
int blah = num + 1;
if ( blah < 0) {
return blah;
}
else {
String error = "Input is too low.";
throw new TooLowException(error);
}
}
This is the exception class:
public class TooLowException extends Exception {
public TooLowException(String response) {
super(response);
}
}
I'm getting the error in Oracle "Unhandled Exception type TooLowException". I've also attempted the try-catch method as well, but it also doesn't work for me. Hopefully this is enough information for someone to point out what I'm doing incorrectly. I need to be set right in my ways of exception handling.
Taken from what info you've given, it seems that you need to have a try/catch block somewhere in your code. Basically somewhere in your application that func(int) method is being called, or needs to be called if you're running into a compiler error telling you the "Unhandled Exception type TooLowException." General rule for exceptions is Handle/Catch or Declare. This can be broken down like this:
Handle/Catch: If you choose to handle the exception, then the "throws" declaration should be removed from the method signature ("public int func(int num) throws TooLowException" becomes "public int func(int num)"). The idea behind this approach is that you as the programmer intend to handle this type of exception because it's specific enough to the method that you don't want external code to have to worry about handling the exception outside of the scope of the method. This requires that you "handle" the exception yourself, by using a try/catch block.
Declare: This is the method you went with. You are stating that whatever class uses this function has the burden of handling the exception with the try/catch block. This would be used if the method you wrote is generic enough that many different applications can use it and that handling the exception should be application specific, i.e., it's up to other developers to handle it in their own way. Some people like to just log things, others like to have a different control flow execute upon receiving certain exceptions.
Here's what works, sorry if it basically answers an exercise you needed to do, but it's in the interest of helping you! Please take time to understand what is happening here:
public class YourClassThisStuffIsIn {
public static int func(int num) throws TooLowException {
int blah = num + 1;
if ( blah < 0) {
return blah;
}
else {
String error = "Input is too low.";
throw new Exception(error);
}
}
public static void main(String[] commandlineArgument){
try {
YourClassThisStuffIsIn.func(3);
} catch (TooLowException tle){
System.out.println("Caught " + e);
}
}
}
When you click run in your IDE, or you run through the console, the JVM looks for the main method with the correct signature. In this case it finds it, and it executes the main method. First line is a try, meaning the JVM has to prepare itself for the possibility of a problem in the application, allowing it to recover in case an exception is thrown. In this case, the only exception that can be thrown is a TooLowException, which you have written how to handle it inside the catch block. Your way of handling it is simply printing the stack trace out, which is fine I think in this situation.
I've changed your example slightly, making your method static just so it's quicker to write. I also suspect that the intent is that the commandLineArgument is meant to be the number passed into the func(int) method, so in that case you're looking at the func method to look like func(Integer.parseInt(commandlineArgument[0])).
Bonus points for you is noticing that parseInt throws a NumberFormatException too, but you will of course remember that java.lang.RuntimeException and its subclasses aren't checked exceptions so there is no requirement to catch them, though it is good practice!

relax exception catch necessity

Is there a possibility in Java to get rid of the necessity to catch non-RuntimeException exceptions? Maybe compiler flags?
I know the reason why the catching is promoted, but want to do simple and straight tools that enforce their requirements. So if something can went wrong I don't like to catch up but exit the application, crashing with a meaningful exception. Usually this ends up like:
try {
connection.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
which introduces 4 lines of code mess, and introduces the wrapping RuntimeException mess on error output. Sometimes it even motivate people to wrap large try ... catch (Throwable ..) blocks around anything, which is the likely cause for our beloved 'Unknown error occured' alert boxes...
you can use throws keyword with method prototype to avoid try-catch block. which eventually throws the exception to JVM's Default Exception handler which halts the application if no catch block's are specified in your code to handle the exception raised.
Crashing the application at the first sight of an exception is very bad practice. Especially when some work is unsaved and the application is using some resources that needs to be freed and cleaned before the application terminates execution. Some very popular software used to do that... and instead of "fixing" the issue, they introduced a data recoverability features on application restart. However the trick, this is not good software engineering.
At the very least, your application should not crash on the first exception/error encountered, but recover with a meaningful message. It is being lazy to just wrap everything in a RuntimeException (or even Throwable) and, especially, not do anything with it.
Java does not support flags of any kind because there are 1) a workaround, and 2) better ways to handle this situation. For example :
1. Handle the exception in the calling method
You can add the throws keyword in your method declaration, up to your static public void main method, which, if not handling the exception, will eventually crash the application with a stacktrace.
class Foo {
public void someMethod(....) throws IllegalArgumentException, IOException {
...
}
static public void main(String...args) throws Throwable {
new Foo().someMethod();
}
}
This method does not offer any means of recoverability and will probably make your user unhappy (with a big meaningless stachtrace if they ran the application from a console, or just nothing at all if they launched it from a shortcut or GUI). Also, if you have some acquired resources, you will not be able to clean them when an exception occurs. At the very least, your main should catch (Throwable e) and output something before throwing the exception above. Something like :
class Foo {
public void someMethod(....) throws IllegalArgumentException, IOException {
...
}
static public void main(String...args) {
try {
new Foo().someMethod();
} catch (...) {
// output or log exception here and, optionally, cleanup and exit
}
}
}
** EDIT **
Consider this scenario : a program is initializing some resource for processing some data, then some runtime exception (or error) occurs during processing, the application crash, but the resources are not released or freed. In Java, however, one could do this
public E doSomething() throws RuntimeException {
// declare a bunch of resources
try {
// process resources with unchecked exceptions
} finally {
// free resources
}
// return some result
}
and cleanly exit the method on error or on success, perhaps even logging the runtime error for "posterity".
2. Log the error and return some meaningful value
Logging is a very good practice. You can show your user some message telling them that the operation could not be executed without crashing the whole thing, and giving you some traces of what and where the user were doing. A simplistic logging system could be :
class Foo {
static private final Logger LOG = Logger.getLogger(Foo.class.getName());
public boolean doSomethingImpl(...) {
boolean result = true;
try {
...
} catch (SomeException e) {
LOG.log(Level.SEVERE, "meaningful message why method could not do something!", e);
result = false;
}
return result;
}
public void doSomething() {
if (!doSomethingImpl(...)) {
// handle failure here
}
}
}
By default, the Logger will output everything to the err output stream, but you can add your own handlers :
// loggers are singletons, so you can retrieve any logger at anytime from
// anywhere, as long as you know the logger's name
Logger logger = Logger.getLogger(Foo.class.getName());
logger.setUseParentHandlers(false); // disable output to err
logger.addHandler(new MyHandler()); // MyHandler extends java.util.logging.Handler
Java already ships with some default logging handlers, one of which writes to file.
etc.
Is there a possibility in Java to get rid of the necessity to catch non-RuntimeException exceptions?
For a checked exception, you can chose between catching the exception and declaring it in the method header as thrown.
Maybe compiler flags?
No. There are no compiler flags to relax this. It is a fundamental part of the language design. Relaxing the checked exception rules via a compiler switch would cause serious library interoperability problems.
I don't think that there's any way around this for the JVM. Your best bet is to have your methods re-throw the exception, which gets rid of the "mess" in your code, and then have your main program throw Exception. This should propagate the error up to the top of your program.
Keep in mind, however, that the place where the exception actually happens is a much better place to let the user know what happened (i.e., exactly what it was doing when this particular IOException happened). You'll lose this resolution if all errors are simply propagated up to the top level.
You do have the ability to throw your exceptions up a level. Here's an example
public class Foo {
public Foo() {
super();
}
public void disconnect(connection) throws IOException {
connection.close();
}
}
Use "Throws" to avoid the error..but it will not be good programimg practice

How can I detect when an Exception's been thrown globally in Java?

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.

Categories