I try to save a duplicate book to my Book domain class for testing. I have a try-catch(Exception ex) to get the error.
BookService bookService
try {
def book = new Book()
book.id = 'Lord of the Flies'
bookSerivce.save(book)
def anotherBook = new Book()
anotherBook.id = 'Lord of the Flies'
bookService.save(anotherBook)
} catch (Exception ex) {
System.out.println(ex.getMessage())
}
I use ex.getMessage(). I am getting this error message. This one is pretty much useless.
could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
On the other hand, I am getting this error message from the command prompt console. This one I can use. It clearly says that I already have a book called 'Lord of the Flies' in the database.
2020-11-02 14:46:39.790 ERROR --- [eduler_Worker-1] o.h.engine.jdbc.spi.SqlExceptionHelper : (conn=665) Duplicate entry 'Lord of the Flies' for key 'PRIMARY'
I understand I should not use the catch-all Exception. I will need to use a more specific Exception class. I already tried catch (SQLException ex) but it did not catch the error. I also tried some others Exception classes but they didn't catch the error either.
It also looks like book.save() and bookSerive.save(book) throw a different Exception.
Would you show me which Exception class I can use in the catch() function to capture the correct error please?
Thanks!
The question and the comments below it aren't especially clear to me but something to investigate is the root cause of the exception:
BookService bookService
try {
def book = new Book()
book.id = 'Lord of the Flies'
bookSerivce.save(book)
def anotherBook = new Book()
anotherBook.id = 'Lord of the Flies'
bookService.save(anotherBook)
} catch (Exception ex) {
System.out.println(ex.getMessage())
Throwable t = ex.getCause()
if(t) {
// interrogate t as the root cause
}
}
Related
I am throwing a custom exception inside the withTransaction method based on a scenarion when author not found.But the issue I am facing is even if the code is enetering inside the exception block for non existent authors, it is not existing out of the flow but continuing with the flow.
Just wanted to check is there anything i am missing here or doing wrong.
Author.withTransaction() {
authStatus -> def author = Author.get(id)
if (!author) {
log.warn "author not found"
throw new NotFoundException('author not found')
}
author.status = 'completed'
author.save()
}
Thanks
Sam
do you really have authStatus -> def author = Author.get(id) all on one line ? or is authStatus -> on withTransaction line, usually a return stops something from continuing but since you are throwing there shouldn't be a need for that. Why not reverse that logic to
if (author) {
do something
return
}
//obviously we didn't have an author since we haven't returned so back to your throw
log.warn "author not found"
throw new NotFoundException('author not found')
I would change that to
Author.withTransaction {
def author = Author.get(id)
if (author) {
author.status = 'completed'
author.save()
return author
}
log.warn "author not found"
throw new NotFoundException('author not found')
}
Personally I would probably wrap entire thing around try catch and not even throw that specific case but instead try to capture get and save errors with one throw at bottom of try catch since you may have got the record but did you manage to save it correctly ?
Can anyone point out why I get an exception when the .results point in the code is executed?
-- note the code has been edited after the quested was answered as per Tatham Oddie's comment. ---
public User Create(User user)
{
try
{
// Check if user exists
if (this.Exists(user.EmailAddress))
{
throw new Exception("User already exists");
}
else
{
var q = this._context.Client().Cypher
.Create("(n:User {f}")
.WithParam("f", "Mike")
.Return(n => n.As<User>());
return q.Results.Single();
}
}
catch (Exception e)
{
throw e;
}
}
Please do not write code like this: "(n:User {FirstName: '" + user.FirstName + "'}". It is a major security risk in your application, and a performance constraint.
Follow the example at https://github.com/Readify/Neo4jClient/wiki/cypher-examples#create-a-user which uses a parameter syntax.
It will be secure.
It will be faster.
It will work.
Got it. Syntax error. Missing bracket.
It seems like if an Exception occurs inside a controller, the view-engine won't go to the intended view, even if the "exception" is caught inside a try-catch block?
or I'm missing something here:
public ActionResult MyController(int? param1, DateTime? param2)
{
MyModel model = new MyModel();
try
{
model = new MyModel();
//AN ERROR HAPPENS HERE (so the code goes to catch the Exception):
model.Connection.Initialize();
}
catch (Exception ex)
{
ViewBag.ErrorMessage = ex.Message;
}
//when I put a break point I get to this following line, however, "MyView" is never displayed!?
return PartialView("MyView", model);
}
You might be getting another exception afterwards, somewhere in your view. Look at the stack trace that displays on the browser page and fix that.
I know how to do generic exception handling in Grails using UrlMappings and an ErrorController for generic exception handling, so that if an exception escapes a controller the user will be sent to a generic error page and the exception will be logged. I also know how to use try/catch blocks to handle specific exceptions and attempt to recover from them.
But in most controllers, I just want to give the user a slightly more specific error message if an exception occurs. So in the create action, I want to tell the user that the item wasn't created. Or in the import action, I want to tell the user that the import failed. Right now, the controllers look like:
class ThingController {
def create = {
try {
// The real controller code, which quickly hands it off to a service
} catch (Exception e) {
handleException(e, "There was an error while attempting to create the Thing")
}
}
def delete = {
try {
// The real controller code, which quickly hands it off to a service
} catch (Exception e) {
handleException(e, "There was an error while attempting to delete the Thing")
}
}
private void handleException(Exception e, String message) {
flash.message = message
String eMessage = ExceptionUtils.getRootCauseMessage(e)
log.error message(code: "sic.log.error.ExceptionOccurred", args: ["${eMessage}", "${e}"])
redirect(action:index)
}
}
Note that the catch blocks don't do anything different based on the type or content of the exception; they're just giving a slightly more descriptive error message based on the controller. The "real" controller code is usually 6-10 lines, so having an additional 4 lines of code just to change the error message seems excessive. In addition, the CodeNarc "CatchException" rule complains, which reinforces my opinion that there has to be a better way to do this. I assume other Grails applications have similar requirements. What is the idiomatic way to specify different error messages based on which action the exception bubbled out of?
I'm interested in answers that come from experience with a particular way of solving this problem, or even better, link to codebases where I can see the solution in practice.
Grails has the mechanism for general handling controller exceptions.
You can do this inside a dedicated Error controller. Regular controllers don’t need to use try/catch.
Controller:
class ThingController {
def create() {
def id = params.id as Long
if (id == null) {
throw new MissingPropertyException("thingId")
}
// The real controller code, which mostly parses things out and hands it
// off to a service.
// Service methods can throws exception
}
}
Add handling 500 error in UrlMappings:
class UrlMappings {
static mappings = {
// Exception handling in ErrorController
"500"(controller: "error")
}
}
ErrorController:
class ErrorController {
def index() {
def exception = request.exception.cause
def message = ExceptionMapper.mapException(exception)
def status = message.status
response.status = status
render(view: "/error", model: [status: status, exception: exception])
}
}
You can handle REST and non-REST exceptions using this approach.
Also there is Declarative Exception Handling plugin but I don’t have an
Update
You can get the specific error messages in Error controller.
When in controller throw new RuntimeException ("There was an error while attempting to delete the Thing"), then in error controller request.exception.cause.message will show message: "There was an error while attempting to delete the Thing".
See also How to know from where was thrown error 500 (Grails)
I create custom error pages based on annotations on the controllers, giving common exception handling procedures across several controllers.
class ErrorsController {
def index() {
def initialController = request.exception?.className
if (initialController) {
def controller = grailsApplication.getArtefact("Controller", initialController).getReferenceInstance()
// do some rendering based on the annotations
render "Controller: ${initialController}, annotations ${controller.getClass().getDeclaredAnnotations()}"
return
}
render 'no initial controller'
}
For some reason the view ErrorPage is not being call even through an exception of type "InvalidOperationExcepion" is being thrown.
[HandleError(View = "ErrorPage", ExceptionType = typeof(InvalidOperationException))]
public ActionResult Request(RequestIn requestin)
{
try
{
var emailService = new EmailServices();
// exception is thrown from some WCF service!
var error = emailService.SendMail("to#someting.com", "from#someting.com", "Request", message, message);
}
catch (Exception ex)
{
}
ViewData["Message"] = "Email has been sent!";
return View("Confirmation");
}
Any ideas!
That's because you handled the exception. Remove the try/catch block.
#frennky is correct in saying it doesn't catch it because you handled the exception. If you still need that try catch you could always rethrow the exception in the catch block. That way you can perform any logging or other cleanup before it is handled by the HandleError attribute.