I want to Throw custom exception but i Got error like :
Error processing request. org.jboss.resteasy.spi.UnhandledException: com.daksa.restmockva.exception.InsufficientBalanceException: Insufficient Balance ........... blah-blah.... ​Caused by: com.daksa.restmockva.exception.InsufficientBalanceException: Insufficient Balance
Here is my TransferService.java :
public Transaction transfer(TransactionModel param) throws InsufficientBalanceException{
Transaction transaction = new Transaction();
transaction.setId(param.getId());
transaction.setSrcAccountId(param.getSrcAccountId());
transaction.setDstAccountId(param.getDstAccountId());
transaction.setAmount(param.getAmount());
transaction.setTransactionTimestamp(new Date());
transaction.setTransactionDate(new Date());
Account accountSrc = accountRepository.getAccountById(param.getSrcAccountId());
Account accountDst = accountRepository.getAccountById(param.getDstAccountId());
if (!accountSrc.getAllowNegativeBalance() && accountSrc.getBalance().compareTo(param.getAmount()) < 0) {
throw new InsufficientBalanceException("Insufficient Balance");
}
accountSrc.setBalance(accountSrc.getBalance().subtract(param.getAmount()));
accountDst.setBalance(accountDst.getBalance().add(param.getAmount()));
entityManager.merge(accountSrc);
entityManager.merge(accountDst);
entityManager.persist(transaction);
return transaction;
}
And here is my TransferResources.java :
#Transactional
#POST
#Path("transfer")
public Transaction doTransfer(TransactionModel param) throws InsufficientBalanceException {
return transactionService.transfer(param);
}
Here is my InsufficientBalanceException.java :
public class InsufficientBalanceException extends Exception {
public InsufficientBalanceException(String errorMessage) {
super(errorMessage);
}
}
Thank You.
I would say, that you need to implement ExceptionMapper for your InsufficientBalanceException
Related
I'm trying to implement a web service using Jersey 2.22.2 and Jetty 9.1.1.v20140108 with exception mapping. The following class represents an Exception class with Mapper implemented.
#Provider
public class NotFoundException extends Exception implements ExceptionMapper<NotFoundException> {
private static final long serialVersionUID = 1L;
public NotFoundException() {
}
public NotFoundException(String s) {
super(s);
}
#Context
private UriInfo uriInfo;
#Override
public Response toResponse(NotFoundException e) {
Status status = Status.NOT_FOUND;
ErrorWrapper errorWrapper = new ErrorWrapper();
errorWrapper.setStatusCode(status.getStatusCode());
errorWrapper.setTitle(status.getReasonPhrase());
errorWrapper.setErrorMessage("The resource you're looking for cannot be found.");
errorWrapper.setApiPath(uriInfo.getAbsolutePath().getPath());
return Response.status(status).entity(errorWrapper).type(MediaType.APPLICATION_JSON).build();
}
}
To test, whether this is working or not, I created an endpoint that simply throws the above exception, like this:
#GET
#Path("test")
#Produces(MediaType.APPLICATION_JSON)
public Response test() throws NotFoundException {
throw new NotFoundException();
}
Calling this endpoint returns a JSON, like this:
{
"statusCode": 404,
"title": "Not Found",
"errorMessage": "The resource you're looking for cannot be found.",
"apiPath": "/users/test"
}
From that, I kinda safely assumed that the exception mapping is working.
Now, what I'm trying to do is to throw this exception, if DAO method returns a null object, for example when trying to fetch a database row that doesn't exist yet. Following are my implementation attempts:
DAO:
public User getUserById(Integer id) throws NotFoundException {
try (DSLContext ctx = new DSLContextFactory("iotrest")
.getDSLContext(getDbDataSource("iotrest"))) {
User user = queries.getUserById(ctx, id)
.fetchOne()
.into(User.class);
if (user == null
|| user.getId() == null) {
throw new NotFoundException("User with id " + id + " not found");
}
UserAccessRights userAccessRights = queries.getUserAccessRights(ctx, user.getId())
.fetchOne()
.into(UserAccessRights.class);
if (userAccessRights == null) {
throw new NotFoundException("Access rights not found for user id " + id);
}
setUserAccessRights(user, userAccessRights);
return user;
}
}
Service:
public User getUserById(Integer id) throws NotFoundException {
return userDao.getUserById(id);
}
Resource:
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getUserById(#PathParam("id") Integer id) throws NotFoundException {
User user = new UserService().getUserById(id);
return Response.ok(user).build();
}
But, when I call the endpoint using an id that doesn't exist yet(2), and get a NullPointerException, I'm still getting a HTTP 500 Request Failed from Jetty, instead of 404 from NotFoundException, like this:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1" />
<title>Error 500 </title>
</head>
<body>
<h2>HTTP ERROR: 500</h2>
<p>Problem accessing /users/2. Reason:
<pre> Request failed.</pre>
</p>
<hr /><i><small>Powered by Jetty://</small></i>
</body>
</html>
Could really use some help with this.
You are not throwing the NotFoundException.
Your code is throwing a NullPointerException.
public User getUserById(Integer id) throws NotFoundException {
try (DSLContext ctx = new DSLContextFactory("iotrest")
.getDSLContext(getDbDataSource("iotrest"))) {
User user = queries.getUserById(ctx, id)
//The NullPointerException is coming from the following line
.fetchOne()
.into(User.class);
if (user == null
|| user.getId() == null) {
throw new NotFoundException("User with id " + id + " not found");
}
UserAccessRights userAccessRights = queries.getUserAccessRights(ctx, user.getId())
.fetchOne()
.into(UserAccessRights.class);
if (userAccessRights == null) {
throw new NotFoundException("Access rights not found for user id " + id);
}
setUserAccessRights(user, userAccessRights);
return user;
}
}
You need to change your code to something like this:
public User getUserById(Integer id) throws NotFoundException {
try (DSLContext ctx = new DSLContextFactory("iotrest")
.getDSLContext(getDbDataSource("iotrest"))) {
User user = queries.getUserById(ctx, id);
if (user == null
|| user.getId() == null) {
throw new NotFoundException("User with id " + id + " not found");
}
user.fetchOne()
.into(User.class);
}
UserAccessRights userAccessRights = queries.getUserAccessRights(ctx, user.getId())
.fetchOne()
.into(UserAccessRights.class);
if (userAccessRights == null) {
throw new NotFoundException("Access rights not found for user id " + id);
}
setUserAccessRights(user, userAccessRights);
return user;
}
}
#galusben's suggestion was instrumental in finding the solution. Clearly, this line was throwing a NPE.
User user = queries.getUserById(ctx, id)
.fetchOne()
.into(User.class);
So, basically what I did was, before lodging the resultset in User, I checked whether the record itself existed or not in the table, like this.
UsersRecord usersRecord = queries.getUserById(ctx, id).fetchOne();
Then, did a null check on that object, and proceed to store record into pojo.
if (usersRecord == null) {
throw new NotFoundException("User with id " + id + " not found");
}
User user = usersRecord.into(User.class);
Tested the endpoint like this:
http://localhost:7000/users/2
The server is now finally returning NotFoundException
{
"statusCode": 404,
"title": "Not Found",
"errorMessage": "The resource you're looking for cannot be found.",
"apiPath": "/users/2"
}
Is there a way I can return internal server error with the exception details?
For example if I have something like the following:
[HttpPost]
public IHttpActionResult test(MyDto dto)
{
using (var transaction = _unitOfWork.BeginTransaction())
{
try
{
//do some stuff
transaction.Commit();
return Ok();
}
catch (Exception ex)
{
transaction.Rollback();
return InternalServerError(new Exception(ex.Message));
}
}
}
Which give me the following. but as you can see there is no inner exception details to provide any meaningful information.
{
"message": "An error has occurred.",
"exceptionMessage": "An error occurred while updating the entries. See the
inner exception for details.",
"exceptionType": "System.Exception",
"stackTrace": null
}
Basically I would like some more info regarding the exception as an when it occurs so that I can troubleshoot?
The easiest way to expose the exception details is to set the configuration property IncludeErrorDetailPolicy = Always in your HttpConfiguration or. Web.conf.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/configuring-aspnet-web-api
After that, you can throw your execption and asp.net creates the InternalServerError-Response.
Another way is to create your own error object and retuns it with the information.
But you should be careful with providing to much information about your internal server information for security reasones.
public static void Register(HttpConfiguration config)
{
Logger.Info("WebApiConfig: Register: Start");
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
// ...
}
[HttpPost]
public IHttpActionResult test(MyDto dto)
{
using (var transaction = _unitOfWork.BeginTransaction())
{
try
{
//do some stuff
transaction.Commit();
return Ok();
}
catch (Exception)
{
transaction.Rollback();
throw;
}
}
}
i have a restcontroller with following Code
#RequestMapping(method = RequestMethod.POST, value = "/student")
public void addTopic(#RequestBody Student student) {
student.setPassword(bCryptPasswordEncoder.encode(student.getPassword()));
studentService.addStudent(student);
}
but if the json data doesn't match the Student object, or is wrong formatted an com.fasterxml.jackson.core.JsonParseException: Unexpected character ('"' (code 34)) ist thrown.
what is the best practice to prevent that
I've found that I need to catch JsonProcessingException (which JsonParseException extends from) in the #ExceptionHandler rather than JsonParseException
#ControllerAdvice
public class FeatureToggleControllerAdvice {
#ExceptionHandler(JsonProcessingException.class)
public ResponseEntity<JSONAPIDocument> handleJsonParseException(JsonProcessingException ex) {
final Error error = new Error();
error.setId(UUID.randomUUID().toString());
error.setStatus(HttpStatus.BAD_REQUEST.toString());
error.setTitle(ex.getMessage());
return new ResponseEntity<>(JSONAPIDocument
.createErrorDocument(Collections.singleton(error)), HttpStatus.NOT_FOUND);
}
}
Using JsonParseException in the above sample and nothing is caught, but using JsonProcessingException works as expected.
Use Spring ExceptionHandler to do that
You could specify an ExceptionHandler based on Exception types and also apply the error codes you want to use.
#ExceptionHandler(JsonParseException.class)
public JacksonExceptionHandler {
public ResponseEntity<String> handleError(final Exception exception) {
HttpStatus status = HttpStatus.BAD_REQUEST;
if (exception != null) {
LOGGER.warn("Responding with status code {} and exception message {}", status, exception.getMessage());
return new ResponseEntity<>(exception.getMessage(), status);
}
}
Furthermore you could make use of javax.validation to validate the entity you receive and then Spring Boot will do all the validation automagically. Just add #Valid to the body.
I'm trying to unit test my controller and the specific case which is : my service return a Mono.Empty, I throw a NotFoundException and I wan't to make sure I'm getting a 404 exception
here's my controller :
#GetMapping(path = "/{id}")
public Mono<MyObject<JsonNode>> getFragmentById(#PathVariable(value = "id") String id) throws NotFoundException {
return this.myService.getObject(id, JsonNode.class).switchIfEmpty(Mono.error(new NotFoundException()));
}
Here's my controller advice :
#ControllerAdvice
public class RestResponseEntityExceptionHandler {
#ExceptionHandler(value = { NotFoundException.class })
protected ResponseEntity<String> handleNotFound(SaveActionException ex, WebRequest request) {
String bodyOfResponse = "This should be application specific";
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found");
}
}
and my test :
#Before
public void setup() {
client = WebTestClient.bindToController(new MyController()).controllerAdvice(new RestResponseEntityExceptionHandler()).build();
}
#Test
public void assert_404() throws Exception {
when(myService.getobject("id", JsonNode.class)).thenReturn(Mono.empty());
WebTestClient.ResponseSpec response = client.get().uri("/api/object/id").exchange();
response.expectStatus().isEqualTo(404);
}
I'm getting a NotFoundException But a 500 error not a 404 which mean my advice hasn't been called
stack trace :
java.lang.AssertionError: Status expected:<404> but was:<500>
> GET /api/fragments/idFragment
> WebTestClient-Request-Id: [1]
No content
< 500 Internal Server Error
< Content-Type: [application/json;charset=UTF-8]
Content not available yet
any idea ?
I believe you can delete this controller advice and just have the following:
#GetMapping(path = "/{id}")
public Mono<MyObject<JsonNode>> getFragmentById(#PathVariable(value = "id") String id) {
return this.myService.getObject(id, JsonNode.class)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)));
}
As for ResponseEntityExceptionHandler, this class is part of Spring MVC so I don't think you should use it in a WebFlux application.
I have some methods which throws some exception, and I want to use AspectJ around advise to calculate the execution time and if some exception is thrown and to log into error log and continue the flow by re-throwing the exception.
I tried to achieve this by following but eclipse says "Unhandled Exception type".
Code-against whom AspectJ is to used :-
public interface Iface {
public void reload() throws TException;
public TUser getUserFromUserId(int userId, String serverId) throws ResumeNotFoundException, TException;
public TUser getUserFromUsername(String username, String serverId) throws ResumeNotFoundException, TException;
public TResume getPartialActiveProfileFromUserId(int userId, int sectionsBitField, String serverId) throws ResumeNotFoundException, UserNotFoundException;
public TResume getPartialActiveProfileFromUsername(String username, int sectionsBitField, String serverId) throws ResumeNotFoundException, UserNotFoundException, TException;
}
Code AspectJ :-
public aspect AspectServerLog {
public static final Logger ERR_LOG = LoggerFactory.getLogger("error");
Object around() : call (* com.abc.Iface.* (..)) {
Object ret;
Throwable ex = null;
StopWatch watch = new Slf4JStopWatch();
try {
ret = proceed();
} catch (UserNotFoundException e) {
ex = e;
throw e;
} catch (ResumeNotFoundException e) {
ex = e;
throw e;
} catch (Throwable e) {
ex = e;
throw new RuntimeException(e);
} finally {
watch.stop(thisJoinPoint.toShortString());
if (ex != null) {
StringBuilder mesg = new StringBuilder("Exception in ");
mesg.append(thisJoinPoint.toShortString()).append('(');
for (Object o : thisJoinPoint.getArgs()) {
mesg.append(o).append(',');
}
mesg.append(')');
ERR_LOG.error(mesg.toString(), ex);
numEx++;
}
}
return ret;
}
}
Please help why this AspectJ is not working.
you can avoid catching the exceptions and just use a try/finally block without the catch.
And if you really need to log the exception you can use an after throwing advice, like this:
public aspect AspectServerLog {
public static final Logger ERR_LOG = LoggerFactory.getLogger("error");
Object around() : call (* com.abc.Iface.* (..)) {
StopWatch watch = new Slf4JStopWatch();
try {
return proceed();
} finally {
watch.stop(thisJoinPoint.toShortString());
}
}
after() throwing (Exception ex) : call (* com.abc.Iface.* (..)) {
StringBuilder mesg = new StringBuilder("Exception in ");
mesg.append(thisJoinPoint.toShortString()).append('(');
for (Object o : thisJoinPoint.getArgs()) {
mesg.append(o).append(',');
}
mesg.append(')');
ERR_LOG.error(mesg.toString(), ex);
}
}
I'm afraid you cannot write advice to throw exceptions that aren't declared to be thrown at the matched join point. Per: http://www.eclipse.org/aspectj/doc/released/progguide/semantics-advice.html :
"An advice declaration must include a throws clause listing the checked exceptions the body may throw. This list of checked exceptions must be compatible with each target join point of the advice, or an error is signalled by the compiler."
There has been discussion on the aspectj mailing list about improving this situation - see threads like this: http://dev.eclipse.org/mhonarc/lists/aspectj-dev/msg01412.html
but basically what you will need to do is different advice for each variant of exception declaration. For example:
Object around() throws ResumeServiceException, ResumeNotFoundException, TException:
call (* Iface.* (..) throws ResumeServiceException, ResumeNotFoundException, TException) {
that will advise everywhere that has those 3 exceptions.
There is an "ugly" workaround - I found them in Spring4 AbstractTransactionAspect
Object around(...): ... {
try {
return proceed(...);
}
catch (RuntimeException ex) {
throw ex;
}
catch (Error err) {
throw err;
}
catch (Throwable thr) {
Rethrower.rethrow(thr);
throw new IllegalStateException("Should never get here", thr);
}
}
/**
* Ugly but safe workaround: We need to be able to propagate checked exceptions,
* despite AspectJ around advice supporting specifically declared exceptions only.
*/
private static class Rethrower {
public static void rethrow(final Throwable exception) {
class CheckedExceptionRethrower<T extends Throwable> {
#SuppressWarnings("unchecked")
private void rethrow(Throwable exception) throws T {
throw (T) exception;
}
}
new CheckedExceptionRethrower<RuntimeException>().rethrow(exception);
}
}