I want to throw a custom error class when a user searches my repo with an invalid ID. This should be very straight forward, but I cannot seem to catch any errors thrown by JpaRepository. I have made several attempts to solve this, but the following is my most straight forward attempt:
try {
Object obj = repository.getOne(id)
}
catch (EntityNotFoundException e) {
throw CustomException("message");
}
When running this in a debugger, repository throws the exact exception I am expecting javax.persistence.EntityNotFoundException, but the code simply skips over my catch statement and the function returns with an error.
I tried using repository.findById(id) with similar results. I also tried catching Exception and Throwable. Any ideas? I will add more information to my post if it ends up my problem is not immediately obvious.
getOne() is just a wrapper for EntityManager.getReference(). That method will not throw any exception.
It returns an uninitialized proxy, assuming that the entity indeed exists. It doesn't get the entity state from the database, and thus doesn't even know if it exists. It assumes it does.
You'll only get an exception later, if you try to access the state of the entity.
Use findById()/findOne(), check if you get a non-empty/non-null result (because these methods don't throw any exception if the entity doesn't exist, they return empty or null), and throw your exception if that's the case.
You can try this:
try {
Object obj = repository.findById(id).orElseThrow(EntityNotFoundException::new);
}
catch (EntityNotFoundException e) {
throw CustomException("message");
}
You need to annotate your repository class with #Repository annotation to perform wrapping of exceptions to specific persistence exceptions.
What regarding question - you don't need to use getOne() with potential exception, but could use some other methods without throwing errors in case if entity not present, like findById() or another one that return Optional<> object
you can catch DataAccessException instead of EntityNotFoundException
try {
Object obj = repository.getOne(id)
}
catch (DataAccessException e) {
throw CustomException("message");
}
Related
In IntelliJ I'm working on some code that retrieves entities from Google Cloud DataStore, using a try catch block like this:
try {
T dataAccessObject = class.newInstance();
entity = datastore.get(KeyFactory.createKey(dataAccessObject.GetEntityName().toString(), id));
dataModel = (T)dataAccessObject.ToModel(entity);
return dataModel;
} catch (EntityNotFoundException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
}
To me, the empty catch statement for the EntityNotFoundException is a code smell, and I'd rather remove it and allow the exception to be thrown.
When I remove that catch statement however, it causes a compiler error, and I'm not seeing any explanation or rationale as to why removing the statement is invalid.
The datastore.get is calling something that implements the com.google.appengine.api.datastore.DatastoreService interface, which means it's possible for an EntityNotFoundException to be thrown, which can be seen if we look at the constructor as defined in the interface:
com.google.appengine.api.datastore.DatastoreService
public interface DatastoreService extends BaseDatastoreService {
Entity get(Key var1) throws EntityNotFoundException;
Why would I need to catch the exception though? Why do I get the compile error?
Java has two different kinds of exceptions: checked and unchecked.
Checked Exceptions:
Any java.lang.Throwable that does not extend from java.lang.Error or java.lang.RuntimeException.
Must be explicitly handled where they can be thrown. Not doing so results in a compilation error. A checked exception is handled if it is caught in a try-catch block or if the containing method is declared to throws the checked exception.
Unchecked Exceptions:
Any instance of java.lang.Error or java.lang.RuntimeException.
Can be caught and handled, but doesn't need to be. Can also be used in the throws clause of a method signature but doing so is typically considered bad practice. If one wants to document the possibility of an unchecked exception being thrown by a method they should do so in the Javadoc, via #throws.
Based on the compilation error, I can only assume EntityNotFoundException is a checked exception and thus must be handled. For more information, see Java: checked vs unchecked exception explanation.
I agree that an empty catch block is smelly. At the very least, you should log the exception. If you end up doing the same thing for each possible exception, you could rewrite the try-catch like so:
try {
/* Do stuff... */
} catch (EntityNotFoundException | IntantiationException | IllegalAccessException ex) {
// log ex...
}
The above syntax requires Java 7+, I believe.
In my service, have handled DataIntegrityViolationException when calling myCrudRepository.saveAndFlush to handle concurrent persist (insertion) requests. It works and I can catch the exception. After this, I prefer to make sure if the exception is exactly because entity already exists, not due to any other possible unknown issues. So, I call myCrudRepository.exists(entity.getId()) , but DataIntegrityViolationException is thrown again.
Here is my simple code:
private void save(final Employee entity) throws MyAppException {
try{
this.myCrudRepository.saveAndFlush(entity);
}catch (org.springframework.dao.DataIntegrityViolationException e){
// check if the error is really because the entity already exists
// entity.getId() is already generated before any save. it's like National ID
boolean exists = this.myCrudRepository.exists(entity.getId()); // DataIntegrityViolationException is thrown here again!
if (exists)
throw new MyAppException(HttpStatus.CONFLICT, "Entity already exists.");
else
throw e;
}
}
But if I use findOne instead of exists, it works fine. It's somehow strange, but of course it has a technical reason that I'm not good enough to make a guess.
Any idea? Thanks in advance.
The problem is when you are using Transactional method and after the method returns the transaction will auto commit and hibernate will wrap up the exceptions into another one. Actually the exception is occurring when transaction commits and at that time you are out of that method already. To catch the exception from inside the method you can simply use em.flush() after this.myCrudRepository.saveAndFlush(entity);.
I've just started my very first toy-project in java and faced with misunderstanding of how it should be done. I'm using java.util.logging and JUnit4 library.
For example we have something like this:
public class SomeClass {
private static Logger log = Logger.getLogger(SomeClass.class.getName());
public static void SomeMethod() {
try{
...some code...
} catch(Exception e){
log.warning("Something bad happened");
}
}
And the unit-test will be:
#Test
public void SomeClassTest(){
SomeClass.SomeMethod();
}
But there will never be an exception, cause I've already handled it in method.
Should I generate new exception in catch-block? Or may be using junit combined with logging is not a good idea?
A method that does not throw an exception (and returns the expected value if any) is meant to work correctly from the perspective of a user.
So you should use try - catch and logging inside a method, when you can catch an exception and the method will still work correctly (do something else when this error happens for example but still return the expected result or perform the supposed operation).
In this case the unit test should check if the operation was performed correctly (if the object is in the expected state and the result value (in your case void) is correct
You should rethrow the exception (and usually not log it, but that depends) if the method cannot do what it is supposed to do when the exception occurs.
In this case the unit test should check if the operation was performed correctly (if the object is in the expected state and the result value (in your case void) is correct if there is no exception, and if there is an exception it should check if this exception was expected
If you want to test that the exception is thrown then you would have to re-throw, or not catch, the Exception.
Otherwise you can unit test that the class is in the correct state after the exception, i.e. that the exception was correctly handled.
I would say one other thing. Don't catch(Exception e), catch the specific exception you are expecting. Otherwise you will handle other, unexpected, exceptions in the same way and that is really quite dangerous.
You can simply rethrow the caught exception:
public class SomeClass {
private static Logger log = Logger.getLogger(SomeClass.class.getName());
public static void SomeMethod() {
try {
// your stuff
} catch (Exception e) {
log.warning("Something happened");
throw e;
}
}
}
Should I generate new exception in catch-block?
No. don't do that! you can test your existing code! when you only want to log the message but you don't want to handle it in the method that call someMethod() don't throw it!
using junit combined with logging is not a good idea?
both are good ideas and can be used together without problems.
Think about how you can test your method. i would not modify the code just that you can easily test it. because you WANTED to catch the exception and log for a reason.
try verifing what variables or objects are modified in your test-method
public void onClick() throws SQLException
try {
// Do something
} catch(MySQLIntegrityConstraintViolationException e) {
//Can i convert this exception to SQL Exception
}
Can i convert MySQLIntegrityConstraintViolationException to SQLException which is thrown by the method?
But the MySQLIntegrityConstraintViolationException already is a SQLExecption (through inheritence)! So there's no need to rethrow it (just remove the try/catch-block).
Sure you can wrap and rethrow - if you think it adds more information or makes your ideas more general. I think in this case the exception you're catching gives more info than the one you're thinking about.
I wouldn't choose a SQLException, though. It's a checked exception. I think the tide has turned from checked to unchecked exceptions.
Spring wraps SQLExceptions into unchecked DataAccessException that extends RuntimeException. I'd suggest that you follow suit.
Here's how you should do it:
catch(MySQLIntegrityConstraintViolationException e) {
throw new SQLException(e);
}
Don't just pass the message. Give the whole stack trace.
You can use the construtor of SQLException to create one in your Catch Block..
try {
} catch (MySQLIntegrityConstraintViolationException e) {
throw new SQLException(e);
}
Since MySQLIntegrityConstraintViolationException is subclass of SQLException re throwing is unnecessary. If you want to abstract your business logic layer from database specific details, make sure to catch SQL Exceptions in the logic layer so that even if the database is switched logic would still valid.
I'm not sure of why this is happening, but I have a simple setup where a caller's return value is null.
I call a function which might throw registered exceptions. When it does, myXDSConsumerRequestHandler stays null. The problem is that I'm able to recover from the registered events (checked the object on the callee). So how do I call the retrieveDocuments and get my object back?
I understand the flow is broken when the exception is thrown, so should I be catching the exceptions at a higher level?
This is the caller:
try {
myXDSConsumerRequestHandler =
RetrieveDocSetUtil.retrieveDocuments(NIST, multipleRetrieveMap);
} catch (VerboseIllegalArgumentException e) {
} catch (XDSException e) {
}
This is the callee:
public static RetrieveDocumentSetImpl retrieveDocuments(
String repoURL, Map<String, String> docRepoMap)
throws VerboseIllegalArgumentException, XDSException {
RetrieveDocumentSetImpl myXDSConsumerRequestHandler =
new RetrieveDocumentSetImpl(repoURL);
myXDSConsumerRequestHandler.retrieveDocumentSet(docRepoMap);
return myXDSConsumerRequestHandler;
}
Thank you!
If retrieveDocuments() throws an exception then it never gets a chance to return something. The statement myXDSConsumerRequestHandler = RetrieveDocSetUtil.retrieveDocuments() does not finish normally.
It is not possible to both catch an exception from a method and receive the return value.
If retrieveDocuments() has something meaningful it can return to callers even when these exceptions are encountered, then this method should be catching exceptions internally and returning an appropriate return value rather than allowing the exception to propagate up to the calling method.
Your code is executed in the following order:
Call retrieveDocuments
Assign the result to myXDSConsumerRequestHandler
If an exception is thrown during step 1, step 2 will never happen.
In general, you cannot both throw an exception and return a value.
You problem comes from having a methid doing too much. It both obtains a RetrieveDocumentSetImpl and attempts to use it.
RetrieveDocumentSetImpl myXDSConsumerRequestHandler =
new RetrieveDocumentSetImpl(repoURL);
myXDSConsumerRequestHandler.retrieveDocumentSet(docRepoMap);
return myXDSConsumerRequestHandler;
Separate this into two methods:
RetrieveDocumentSetImpl myXDSConsumerRequestHandler =
new RetrieveDocumentSetImpl(repoURL);
return myXDSConsumerRequestHandler;
which either return a handler or fails, throwing an Exception, and
myXDSConsumerRequestHandler.retrieveDocumentSet(docRepoMap);
Then your caller can call the first method, grabbing the return code, and then if they so choose try various things such as cal the second, catching the indidual exceptions they throw.
Here are my suggestions
Add proper handling on public retrieveDocuments(NIST, multipleRetrieveMap) method to ensure that proper parameters are passed to your method. This will address exceptions specially related to VerboseIllegalArgumentException the parameter validation/handling should be done before you pass the paramters to the retrieveDocuments method. Im afraid that if you encounter an exception you can no longer retreive your object for the reason stated by the previous posters It is not possible to both catch an exception from a method and receive the return value. thats why proper validation and handling is very important.
After determining the cause of your exception, define/create your own exceptions. This will save you a lot of time and headache in the future.