Is there a way in Java/Spring with annotations to achieve the following?
For example I have a method:
public void deleteObject(Object object) {
delete(object);
}
I want to send 2 audit events: one when method starts, and second - if method finishes successfully or throws exception.
Actually, I can do it like this:
public void deleteObject(Object object) {
sendAuditEvent("Started deletion of object");
try {
delete(object);
sendAuditEvent("Finished deleting of object successfully");
} catch (Exception ex) {
sendAuditEvent("Finished deleting object with exception");
throw ex;
}
}
But I was wondering if there is a way to do it with annotations? I'd prefer to keep the auditing logic separately and not autowire any beans for sending audit events.
The only thing coming top my mind is to do something like this:
public void deleteObject(Object object) {
startedDeleting(object);
delete(object);
}
#SomeAnnotationOnStartOfMethod
public void startedDeleting(Object object) {
//do nothing
}
public void delete(Object object) {
try {
businessLogicMethodToDelete(object);
methodOnSuccess(object);
} catch (Exception ex) {
methodOnException(object);
throw ex;
}
}
#SomeAnnotationOnSuccess
public void methodOnSuccess(Object object) {
//do nothing
}
#SomeAnnotationOnFailure
public void methodOnException(Object object) {
//do nothing
}
But that looks not nice to me.
What could be a better design solution here?
What you are looking for is called Aspect-oriented programming.
The most commonly used tools to solve this kind of problems are:
AspectJ (cf. also the tutorial on Baeldung),
Spring AOP (cf. also the tutorial on Baeldung)
Related
i have the following problem:
Our java software takes incoming xml-files and parse / validate / makes some magic. Because it's a 24/7 software it's designed to resist single faults, by ignoring single files and proceeding to the next.
I want to know if there is a possible solution to test units e.g with JUnit or TestNG for already catched exceptions.
For example if have a class and function like this
public class ExceptionTest {
public static void throwEx() {
try {
int i = 1 / 0;
} catch (Exception e) {
e.printStackTrace();
}
}
}
Now i want to test if any Exception is catched. If so the test should fail. On the other hand, if i expect certain types of exceptions, the test should succeed.
public class TSTException {
#Test
public void testExceptionThrown() {
ExceptionTest.throwEx();
assert ("ExceptionsCatched.size()", 0)
}
}
I know i could edit my code to provide some kind of global variables like boolean success = true and check those but i am interested if there is another possible solution for my problem.
Thanks,
Dominik
If it is possible to modify the code You could wrap the class containing the logic and catch the exception in the wrapper class.
something like this:
public class SomeService{
public void doSomething() {
int i = 1 / 0;
}
}
public class SomeServiceCatchExceptionWrapper{
private SomeService someService;
public void doSomething() {
try {
someService.doSomething();
} catch (Exception e) {
e.printStackTrace();
}
}
}
So this way you can test both classes individually.
I have two methods at service layer in springs MVC. In one method i am throwing ObjectNotFoundExcetion with my own reason when my record not found. I am calling this method from the first method. In first method I have declared try catch for it and have further code. But once i get the ObjectNotFoundException, the whole transaction rolls back. Hence I am not able to do further processing. Why is the transaction rolling back at service layer ?
public void foo() {
try {
boo();
} catch(ObjectNotFoundException e) {
}
// further code.
}
public void boo() throws ObjectNotFoundException
{
if () {
} else {
throw new ObjectNotFoundException("Record not found");
}
}
I am thinking about how to write tests for my project. At the moment, tests structure is like this:
RealClass
{
method1;
method2;
...
}
and exactly same test class structure:
TestClass {
testMethod1;
testMethod2;
...
}
But, I do not like it, because I am putting too much test cases in one test method...
May be I should use structure like this:
TestClass {
testMethod1Opt1;
testMethod1Opt2;
...
testMethod2Opt1;
...}
How are you writing Unit tests?
Example of my test code: (Very simple test)
public void testIsAppUser() {
// My (Artem`s Zinnatullin) uId
final long artemZinnatullinUId = 172672179;
try {
assertTrue(usersApi.isAppUser(artemZinnatullinUId));
} catch (Exception e) {
fail(e.getMessage());
}
// Pavel`s Durov uId
final long durovUId = 1;
try {
assertFalse(usersApi.isAppUser(durovUId));
} catch (Exception e) {
fail(e.getMessage());
}
// By default uId == current user`s (who has authorized) uId
try {
assertTrue(usersApi.isAppUser(null));
} catch (Exception e) {
fail(e.getMessage());
}
}
What I am thinking about:
public void testIsAppUser1() {
// My (Artem`s Zinnatullin) uId
final long artemZinnatullinUId = 172672179;
try {
assertTrue(usersApi.isAppUser(artemZinnatullinUId));
} catch (Exception e) {
fail(e.getMessage());
}
}
public void testIsAppUser2() {
// Pavel`s Durov uId
final long durovUId = 1;
try {
assertFalse(usersApi.isAppUser(durovUId));
} catch (Exception e) {
fail(e.getMessage());
}
}
public void testIsAppUser3() {
// By default uId == current user`s (who has authorized) uId
try {
assertTrue(usersApi.isAppUser(null));
} catch (Exception e) {
fail(e.getMessage());
}
}
Give me advice please.
Comments:
Instead of try{} catch(){ fail() } just add throws Exception to the test method. JUnit will automatically fail the test for you and preserve the stack trace. This will make bug fixing much easier.
Create small test methods. That creates a name problem: How to come up with lots of good names? The solution here is to name the test after what it logically tests, not which methods it calls.
If you want to see what methods are called, use a code coverage tool like JaCoCo.
So the first test should be called testIsArtemsZinnatullinAppUser(). As a guideline: Whenever you feel like you need a comment to explain what a test does, the test name is wrong. Use whatever you'd write in the comment to create a test name.
The reason why you should have smaller tests is that JUnit stops for the first problem. So if you have 20 tests in one test case and the 3rd fails, 17 tests won't run. But these 17 tests could contain valuable information helping to figure out what is wrong.
If they all succeed, then this is probably a specific problem. If many tests fail, the problem must be in shared code.
Your second way of structuring the tests is a lot better. That way each test method covers a different way for the method to break, so you won't have the case where you fix one bug in a method, then have the test fail a little further down (so that one error prevents you from seeing others). It is a lot more important that the test methods be small and sharply-focused than that the test methods map to the methods of the object being tested.
Also, don't catch exceptions, JUnit will do that for you. Add throws Exception to the signature of each of your test methods. If you want to check that an exception is really thrown, then you can catch it in a test, like:
try {
objectUnderTest.doSomethingThatShouldThrowFooException();
fail("should've thrown an exception before getting here");
}
catch (FooException fooEx) {
// yay. my test passed
}
, but the boilerplate of:
} catch (Exception e) {
fail(e.getMessage());
}
is unnecessary.
I won't repeat what's in the other responses. But just adding this:
Avoid duplication of code construct in your test classes.
Don't hesitate to write explicit failure messages.
Here is something to illustrate what I mean:
public void testIsAppUser1() {
// My (Artem`s Zinnatullin) uId
assertAppUser(172672179,true,"artemZinnatullinUId");
}
public void testIsAppUser2() {
// Pavel`s Durov uId
assertAppUser(1,false,"Pavel`s Durov");
}
public void testIsAppUser3() {
// By default uId == current user`s (who has authorized) uId
assertAppUser(null,true,"current user");
}
private void assertAppUser(Long id, boolean isExpectedAppUser, String userName){
boolean isAppUser = usersApi.isAppUser(id);
if(isExpectedAppUser){
assertTrue("User with id:"+id+"and named:"+userName+" must be an appUser" ,isAppUser);
}else{
assertFalse("User with id:"+id+"and named:"+userName+" cannot be an appUser" ,isAppUser);
}
}
}
Only throw when you have an error that might happen because of an 'exception' don't necassarily throw because you can. The following assumes you are creating your own testing enviorment.
I don't know what your assert methods look like but really they should be the ones throwing if anything. You also don't need a try catch to throw an exception you can do the following:
throw new Exception("msg"); // Or another type of Exception
So implementation:
public void AssertEqual(Object obj1, Object obj2) throws Exception
{
if (!obj1.equals(obj2))
throw new Exception("Objects are not equal");
}
I have multiple cases when I have to deal retrial for DB and networking operations. Everywhere I do it I have the following type of code:
for (int iteration = 1; ; iteration++) {
try {
data = doSomethingUseful(data);
break;
} catch (SomeException | AndAnotherException e) {
if (iteration == helper.getNumberOfRetries()) {
throw e;
} else {
errorReporter.reportError("Got following error for data = {}. Continue trying after delay...", data, e);
utilities.defaultDelayForIteration(iteration);
handleSpecificCase(data);
}
}
}
The issue is that this code pattern is copy-pasted all over my classes. Which is really bad. I can't figure out how to get rid of this for-break-catch copy-paste pattern, since I usually get different exception to handle, I want to log data I failed on (usually also different ways).
Is there a good way to avoid this copy-paste in Java 7?
Edit: I do use guice for dependency injection. I do have checked exceptions. There could be multiple variables instead of just one data and they are all of different type.
Edit2: AOP approach looks as the most promising for me.
Off-hand, I can think of two different approaches:
If the differences in exception handling can be expressed declaratively, you might use AOP to weave the exception handling code around your methods. Then, your business code could look like:
#Retry(times = 3, loglevel = LogLevel.INFO)
List<User> getActiveUsers() throws DatabaseException {
// talk to the database
}
The advantage is that it is really easy to add retry behaviour to a method, the disadvantage is the complexity of weaving the advice (which you only have to implement once. If you are using a dependency injection library, chances are it will offer method interception support).
The other approach is to use the command pattern:
abstract class Retrieable<I,O> {
private final LogLevel logLevel;
protected Retrieable(LogLevel loglevel) {
this.logLevel = loglevel;
}
protected abstract O call(I input);
// subclasses may override to perform custom logic.
protected void handle(RuntimeException e) {
// log the exception.
}
public O execute(I input) {
for (int iteration = 1; ; iteration++) {
try {
return call(input);
} catch (RuntimeException e) {
if (iteration == helper.getNumberOfRetries()) {
throw e;
} else {
handle();
utilities.defaultDelayForIteration(iteration);
}
}
}
}
}
The problem with the command pattern are the method arguments. You are restricted to a single parameter, and the generics are rather unwieldly for the caller. In addition, it won't work with checked exceptions. On the plus side, no fancy AOP stuff :-)
As already suggested, AOP and Java annotations is a good option. I would recommend to use a read-made mechanism from jcabi-aspects:
#RetryOnFailure(attempts = 2, delay = 10, verbose = false)
public String load(URL url) {
return url.openConnection().getContent();
}
Read also this blog post: http://www.yegor256.com/2014/08/15/retry-java-method-on-exception.html
I have implemented the RetryLogic class below which provides reusable retry logic and supports parameters because the code to be retried is in a delegate passed in.
/**
* Generic retry logic. Delegate must throw the specified exception type to trigger the retry logic.
*/
public class RetryLogic<T>
{
public static interface Delegate<T>
{
T call() throws Exception;
}
private int maxAttempts;
private int retryWaitSeconds;
#SuppressWarnings("rawtypes")
private Class retryExceptionType;
public RetryLogic(int maxAttempts, int retryWaitSeconds, #SuppressWarnings("rawtypes") Class retryExceptionType)
{
this.maxAttempts = maxAttempts;
this.retryWaitSeconds = retryWaitSeconds;
this.retryExceptionType = retryExceptionType;
}
public T getResult(Delegate<T> caller) throws Exception {
T result = null;
int remainingAttempts = maxAttempts;
do {
try {
result = caller.call();
} catch (Exception e){
if (e.getClass().equals(retryExceptionType))
{
if (--remainingAttempts == 0)
{
throw new Exception("Retries exausted.");
}
else
{
try {
Thread.sleep((1000*retryWaitSeconds));
} catch (InterruptedException ie) {
}
}
}
else
{
throw e;
}
}
} while (result == null && remainingAttempts > 0);
return result;
}
}
Below is a use example. The code to be retried is within the call method.
private MyResultType getDataWithRetry(final String parameter) throws Exception {
return new RetryLogic<MyResultType>(5, 15, Exception.class).getResult(new RetryLogic.Delegate<MyResultType> () {
public MyResultType call() throws Exception {
return dataLayer.getData(parameter);
}});
}
In case you want to retry only when a specific type of exception occurs (and fail on all other types of exceptions) the RetryLogic class supports an exception class parameter.
Make your doSomething implement an interface, e.g., Runable and create a method containing your code above with doSomething replaced with interface.run(data)
take a look at: this retry utility
this method should work for most use cases:
public static <T> T executeWithRetry(final Callable<T> what, final int nrImmediateRetries,
final int nrTotalRetries, final int retryWaitMillis, final int timeoutMillis)
you can eassily implement an aspect using this utility to do this with even less code.
Extending the approach discusssed already, how about something like this (no IDE on this netbook, so regard this as pseudocode...)
// generics left as an exercise for the reader...
public Object doWithRetry(Retryable r){
for (int iteration = 1; ; iteration++) {
try {
return r.doSomethingUseful(data);
} catch (Exception e) {
if (r.isRetryException(e)) {
if(r.tooManyRetries(i){
throw e;
}
} else {
r.handleOtherException(e);
}
}
}
One thing I would like to add. Most exceptions (99.999%) mean there is something very wrong with your code or environment that needs an admins attention. If your code can't connect to the database it's probably a misconfigured environment there is little point to retrying it just to find out it didn't work the 3rd, 4th, or 5th time either. If you're throwing an exception because the person didn't give a valid credit card number, retrying isn't going to magically fill in a credit card number.
The only situations that are remotely worth retrying is when a system is tremendously strained and things are timing out, but in this situation retry logic is probably going to cause more strain than less (3x for 3 retries on every transaction). But this is what systems do to back down demand (see the apollo lander mission story). When a system is asked to do more than it can it starts dropping jobs and timeouts are the signal the system is strained (or poorly written). You'd be in a far better situation if you just increased the capacity of your system (add more ram, bigger servers, more servers, better algorithms, scale it!).
The other situation would be if you're using optimistic locking and you can somehow recover and auto merge two versions of an object. While I have seen this before I'd caution this approach, but it could be done for simple objects that can be merged without conflicts 100% of the time.
Most exceptions logic should be catch at the appropriate level (very important), make sure your system is in a good consistent state (ie rollback transactions, close files, etc), log it, inform user it didn't work.
But I'll humor this idea and try to give a good framework (well because it's fun like crossword puzzle fun).
// client code - what you write a lot
public class SomeDao {
public SomeReturn saveObject( final SomeObject obj ) throws RetryException {
Retry<SomeReturn> retry = new Retry<SomeReturn>() {
public SomeReturn execute() throws Exception {
try {
// doSomething
return someReturn;
} catch( SomeExpectedBadExceptionNotWorthRetrying ex ) {
throw new NoRetryException( ex ); // optional exception block
}
}
}
return retry.run();
}
}
// framework - what you write once
public abstract class Retry<T> {
public static final int MAX_RETRIES = 3;
private int tries = 0;
public T execute() throws Exception;
public T run() throws RetryException {
try {
return execute();
} catch( NoRetryException ex ) {
throw ex;
} catch( Exception ex ) {
tries++;
if( MAX_RETRIES == tries ) {
throw new RetryException("Maximum retries exceeded", ex );
} else {
return run();
}
}
}
}
I'm trying out Spring for the first time but am having a problem with #Transactional. There are certain parts of my app that I need to log exceptions in the method instead of bubbling them up to, say, main(). The issue though is that those methods which are labeled with #Transactional won't be rolled back if an exception occurs.
In short, this wont' work
#Transactional
public void doStuff() {
try {
//Do something that might cause an Exception
} catch (Exception e) {
log.error("Exception when trying to do stuff", e);
}
}
Because from my understanding the transaction will never be rolled back if an exception occurs.
The only solution I could come up with:
public void doStuff() {
try {
doStuff0();
} catch (Exception e) {
log.error("Error encountered while attempting to join servers", e);
}
}
#Transactional
protected void doStuff0() {
//Do something that might cause an Exception
}
That's ugly though, uses a pattern I don't like, and is in this example almost twice as much code.
Is there another alternative to log the exception AND rollback the transaction?
There is in fact a simple way to do what you want. Architectural Astronaut discussions about if it's a good idea or when it' appropriate aside, sometimes you just need it to work :) :
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
Easy as that.
Just rethrow the exception:
#Transactional
public void doStuff() {
try {
//Do something that might cause an Exception
} catch (Exception e) {
log.error("Exception when trying to do stuff", e);
throw e;
}
}