Reputation: 2329
I have the following insert/update methods in my service:
@Override
public void insertEntity(Entity entity) {
try {
entityDao.insert(entityMapper.entityToEntityDO(entity));
} catch (DataIntegrityViolationException ex){
if(ex.getCause() instanceof SQLIntegrityConstraintViolationException) {
SQLIntegrityConstraintViolationException violationEx = (SQLIntegrityConstraintViolationException) ex.getCause();
if(violationEx.getErrorCode() == 1048 && "23000".equals(violationEx.getSQLState())) {
throw new FieldCannotBeNullException(violationEx.getMessage());
}
}
throw ex;
}
}
@Override
public void updateEntity(Entity entity) {
try {
entityDao.update(entityMapper.entityToEntityDO(entity));
} catch (DataIntegrityViolationException ex){
if(ex.getCause() instanceof SQLIntegrityConstraintViolationException) {
SQLIntegrityConstraintViolationException violationEx = (SQLIntegrityConstraintViolationException) ex.getCause();
if(violationEx.getErrorCode() == 1048 && "23000".equals(violationEx.getSQLState())) {
throw new FieldCannotBeNullException(violationEx.getMessage());
}
}
throw ex;
}
}
As you can see, the actual logic of insertEntity
and updateEntity
is very simple. In order to throw a custom Exception
, I did some database error code check. Since the two methods all need this kind of checking, the code duplicated in both methods, which is obviously a code smell.
How can I eliminate this kind of code duplication?
Upvotes: 3
Views: 3865
Reputation: 1495
You can declare your methods to throw the exception, then try/catch in one place where your methods are called. For example:
public void insertEntity(Entity entity) throws DataIntegrityViolationException {}
public void updateEntity(Entity entity) throws DataIntegrityViolationException {}
try {
insertEntity(entity);
updateEntity(entity);
catch (DataIntegrityViolationException e) {
// handle exception
}
Upvotes: 0
Reputation: 11
You can create Interface like this:
public interface ConsumerWithException<T, V extends Exception> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t) throws V;
}
Use it a private method like:
private void action(ConsumerWithException<Entity, DataIntegrityViolationException> doAction, Entity entity){
try {
doAction.accept(entity);
} catch (DataIntegrityViolationException ex){
if(ex.getCause() instanceof SQLIntegrityConstraintViolationException) {
SQLIntegrityConstraintViolationException violationEx = (SQLIntegrityConstraintViolationException) ex.getCause();
if(violationEx.getErrorCode() == 1048 && "23000".equals(violationEx.getSQLState())) {
throw new FieldCannotBeNullException(violationEx.getMessage());
}
}
throw ex;
}
}
Upvotes: 1
Reputation: 3267
You can put the code inside the catch block into a separate method.
Alternatively, You can catch Exception
and write a handler method to handle the exceptions if in future you expect to handle multiple exceptions there.
Upvotes: 0
Reputation: 726
Extract the common catch-block to a method which throws DataIntegrityViolationException
.
Upvotes: 2