Handling stack traces with unknown exception classes - java

I'm implementing a session bean that throws ApplicationExceptions.
These exceptions have chained stack traces that may contain exceptions whose classes aren't available on the client. Something like:
#Override
public void doSomethingSpecial(MyObject o) throws MyException {
try {
legacySystem.handle(o);
} catch (LegacyException e) {
logger.warn(e.getMessage(), e);
throw new MyException(e);
}
}
Here it's possible that the client gets an exception it doesn't have the class for. This can result in:
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at sun.proxy.$Proxy0.doSomethingSpecial(Unknown Source)
at com.myapp.client.Client.main(Client.java:56)
Caused by: java.lang.ClassNotFoundException: MyLegacyException
I don't want the client to know all the possible exceptions that can be thrown on the server side, but having a stack trace is never bad.
How do you handle these problems? Is it a passable solution to implement an Interceptor that decouples the stack trace when the exception is sent back to the client? But then the Interceptor should handle only calls via the RemoteInterface, because internally I'm interested in the whole stack trace.

It depends on your client type. If a client is another team which is developing another component or subsytem, I'm agree with you about:
Having a stack trace is never bad
But if they are customers who have no idea about your application internals, so there is no reason for them to know your exception classes or even see your stack traces. It would be nice to have a protocol which force you to catch all exceptions and wrap them in a high level exception class with a error_code property. This way, you can have a specific error code for each catch statement in your application and you will give your clients a list of these codes.
Anyway, from technical view, if your clients doesn't have access to your internal Exception classes, so they can't have access to your stack trace without referred ClassNotFoundException. If you really want them to see the stack trace, one solution could be to have an Aspect which sits just on the most upper layer of your API (which is going to be called by clients) and catches all the exceptions, writes their stack traces in a String and sends this as a property of the final exception which is going to be caught by caller. This way, the caller can access the stack trace as a formatted String property of the exception.
Edit:
You can even configure your build script, so that this Aspect never be a part of your release versions. So you can give this stack trace messages just in your debug version.

I thought about little roundabout solution, but this is only untested speculation.
You initialize your external exception with internal exception. But if we look at javadoc of Throwable we can see methods get and setStackTrace(StackTraceElement[] stackTrace)
StackTraceElement is initialized with strings. So maybe you can get stack trace from internal exception and set it into your external exception (MyException).

Since RMI settles on Serialization you can use Serialization features to conditionally replace exceptions.
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
public class CarryException extends RuntimeException implements Serializable
{
final String exceptionClass;
public CarryException(Exception cause)
{
super(cause.getMessage());
exceptionClass=cause.getClass().getName();
setStackTrace(cause.getStackTrace());
}
#Override
public String getMessage()
{
// if we get here, reconstructing the original exception did not work
return exceptionClass+": "+super.getMessage();
}
/** Invoked by Serialization to get the real instance */
final Object readResolve() throws ObjectStreamException
{
try
{
Exception ex = Class.forName(exceptionClass).asSubclass(Exception.class)
.getConstructor(String.class).newInstance(super.getMessage());
ex.setStackTrace(getStackTrace());
return ex;
}
catch(InstantiationException|IllegalAccessException|ClassNotFoundException
| IllegalArgumentException|InvocationTargetException|NoSuchMethodException
| SecurityException ex)
{
// can't reconstruct exception on client side
}
return this; // use myself as substitute
}
}
Now you can throw any exception to the client by throw new CarryException(originalException);. The CarryException will always record the stack trace and message of the original exception and recreate the original exception at client side if the class is available. Otherwise the client sees the CarryException so obviously that one exception type must be known on the the client side.
The exception type must have the standard constructor taking a message String for the reconstruction to work. (All other things would be too complicated). But most exception types have that.
There is another catch: replacing via Serialization does only work if Serialization is involved so you must not invoke the methods on the implementation class directly when beeing inside the same JVM. Otherwise you see the CarryException unconditionally. So you have to use a stub even locally, e.g.
((MyRemoteInterface)RemoteObject.toStub(myImplementation)).doSomethingSpecial();
Update
If MyException is known to the client and only LegacyException is not, of course the following works:
catch (LegacyException e) {
logger.warn(e.getMessage(), e);
MyException me=new MyException(e.toString());
me.setStackTrace(e.getStackTrace());
throw me;
}

Related

Spring Boot Application - Is it considered bad practice to throw EntityExists - or EntityNotFoundException from Service to Controller?

My understanding of these exceptions is if an object in the database that you are looking for doesn't exist or exists these gets thrown? But is it ok for myself to use when I want to handle different cases in MyServiceClass.
Is it bad practice to throw these exceptions or should I create my own Exceptions for let's say if a user dont exist in the database?
How does it work in a real production?
Thanks in advance!
You should only implement a custom exception if it provides a benefit compared to Java's standard exceptions. The class name of your exception should end with Exception.
But it’s sometimes better to catch a standard exception and to wrap it into a custom one. A typical example for such an exception is an application or framework specific business exception. That allows you to add additional information and you can also implement a special handling for your exception class.
When you do that, make sure to set the original exception as the cause. The Exception class provides specific constructor methods that accept a Throwable as a parameter. Otherwise, you lose the stack trace and message of the original exception which will make it difficult to analyze the exceptional event that caused your exception.
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e);
}
}
Try not to create new custom exceptions if they do not have useful information for client code.
And if you make a custom exception be sure to:
Document the Exceptions You Specify
Throw Exceptions With Descriptive Messages
Catch the Most Specific Exception First
Don’t Log and Throw

catching and re throwing same custom exception [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I have a Spring JobRunner Component that has a run() method which throws my custom exception:
public Response run(final Request request, final String id) {
try {
execution = jobLauncher.run(job, parameters);
} catch (JobExecutionAlreadyRunningException e) {
throw new MyCustomException("already running ", e);
} catch (JobRestartException e) {
throw new MyCustomException("Restart Exception", e);
}
return generateResponse(request, id, execution);
}
In my service class, I call this run() method inside process()
protected Response process(final Request request, final String id) {
//get entity
//save
//bla bla
Response response;
try {
response = jobRunner.run(request, id);
updateStatus(entity, response.getStatus(), "");
} catch (MyCustomException ex) {
updateStatus(entity, FAILED);
throw new MyCustomException(ex.getMessage(), ex);
}
}
You will notice I am catching MyCustomException and rethrowing again. I have to catch because I need to update the status accordingly here in the service class as it has a repository dependency to update status in db for tracking purpose.
I am also rethrowing because attached to this custom exception is a ControllerAdvice for api requests so it responds accordingly.
What I would like to know, is this a good design or a bad practice? What could I change if anything?
This can be a good practice, bad practice, or unnecessary, depending on the case. When you catch and throw a new exception with:
throw new MyCustomException(ex.getMessage(), ex);
you get a new exception with a new stack trace that points to this line of code, and you maintain the original exception with its stack trace as the "cause".
This is a good practice if the original exception was produced in an asynchronous context. This is a common problem with reactive programming: when an exception is created by some asynchronous operation, its stack trace has no reference to the calling code. Creating a new exception at the point of capture adds the context needed to find the operation that resulted in the exception.
This is a bad practice if the original exception includes privileged information that should remain secret. In this case the new exception should be created without a cause, and the original exception should be logged. The code should look like:
log.error(ex);
throw new MyCustomException("whoopsie");
In other cases, creating a new exception instance is unnecessary. Just re-throw the original exception.
} catch (MyCustomException ex) {
updateStatus(entity, FAILED);
throw ex;
}
This is a very good question actually.
I see that you are separating concerns by layers. You should do the same with your exceptions.
And you should also be aware of the type of exceptions you are throwing (checked vs. unchecked).
JobCustomException
I'd advise you to create a Checked Exception for your Jobs. Here you would encapsulate all the details related to a job error. And by using a checked exception, you are achieving two things:
You are warning the calling class that an exception may be thrown and can be handled.
You are signalling the developer that this may be a recoverable error.
From the Java Docs:
If a client can reasonably be expected to recover from an exception,
make it a checked exception. If a client cannot do anything to recover
from the exception, make it an unchecked exception
ServiceCustomException
Then, another exception can be created for your service layer. This kind of exception should extend from RuntimeException if you believe it may no longer be handled (except for the ControllerAdvice, of course).
It may also be useful to transform or introduce extra information.
Finally, while you may have a single generic Job exception, there may be many client classes (services) that may throw different Runtime-based exceptions to add further business detail about the business flow where the error occurred.
Throwing, catching, and re-throwing
You are doing it right, as long as you pay attention to the aforementioned bullets. This is the whole point of throwing exceptions.
Exceptions don't need to be terminal errors, although there is some kind of belief that RuntimeExceptions are the only accepted type of Exceptions.
Most well-designed object's APIs and frameworks, make use of proper Checked exceptions to communicate to the client classes what are the errors that may occur.

How can I override Dropwizard's default resource exception handling?

Suppose I've got an endpoint in Dropwizard, say
#GET
public Response foo() { throw new NullPointerException(); }
When I hit this endpoint it logs the exception and everything, which is great! I love it. What I love less is that it returns a big status object to the user with status: ERROR (which is fine) as well as a gigantic stack trace, which I'm less excited about.
Obviously it's best to catch and deal with exceptions on my own, but from time to time they're going to slip through. Writing a try catch block around the entire resource every time is fine, but (a) it's cumbersome, and (b) I always prefer automated solutions to "you have to remember" solutions.
So what I would like is something that does the following:
Logs the stack trace (I use slf4j but I assume it would work for whatever)
Returns a general purpose error response, which does not expose potentially privileged information about my server!
I feel like there must be a built-in way to do this -- it already handles exceptions in a relatively nice way -- but searching the docs hasn't turned up anything. Is there a good solution for this?
As alluded to by reek in the comments, the answer is an ExceptionMapper. You'll need a class like this:
#Provider
public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException> {
#Override
public Response toResponse(RuntimeException runtime) {
// ...
}
}
You can do whatever logging or etc. you like in the toResponse method, and the return value is what is actually sent up to the requester. This way you have complete control, and should set up sane defaults -- remember this is for errors that slip through, not for errors you actually expect to see! This is also a good time to set up different behaviors depending on what kind of exceptions you're getting.
To actually make this do anything, simply insert the following line (or similar) in the run method of your main dropwizard application:
environment.jersey().register(new RuntimeExceptionMapper());
where environment is the Environment parameter to the Application's run method. Now when you have an uncaught RuntimeException somewhere, this will trigger, rather than whatever dropwizard was doing before.
NB: this is still not an excuse not to catch and deal with your exceptions carefully!
Add the following to your yaml file. Note that it will remove all the default exception mappers that dropwizard adds.
server:
registerDefaultExceptionMappers: false
Write a custom exception mapper as below:
public class CustomExceptionMapper implements ExceptionMapper<RuntimeException> {
#Override
public Response toResponse(RuntimeException runtime) {
// ...
}
}
Then register the exception mapper in jersey:
environment.jersey().register(new CustomExceptionMapper());
Already mentioned this under the comments, but then thought I would give it a try with a use case.
Would suggest you to start differentiating the Exception that you would be throwing. Use custom exception for the failures you know and throw those with pretty logging. At the same RuntimeException should actually be fixed. Anyhow if you don't want to display stack trace to the end user you can probably catch a generic exception, log the details and customize the Response and entity accordingly.
You can define a
public class ErrorResponse {
private int code;
private String message;
public ErrorResponse() {
}
public ErrorResponse(int code, String message) {
this.code = code;
this.message = message;
}
... setters and getters
}
and then within you resource code you can modify the method as -
#GET
public Response foo() {
try {
...
return Response.status(HttpStatus.SC_OK).entity(response).build();
} catch (CustomBadRequestException ce) {
log.error(ce.printStackTrace());
return Response.status(HttpStatus.SC_BAD_REQUEST).entity(new ErrorResponse(HttpStatus.SC_BAD_REQUEST, ce.getMessage())).build();
} catch (Exception e) {
log.error(e.printStackTrace(e));
return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage())).build();
}
}
This article details Checked and Unchecked Exceptions implementation for Jersey with customized ExceptionMapper:
https://www.codepedia.org/ama/error-handling-in-rest-api-with-jersey/
Official Dropwizard documentation also covers a simpler approach, just catching using WebApplicationException:
#GET
#Path("/{collection}")
public Saying reduceCols(#PathParam("collection") String collection) {
if (!collectionMap.containsKey(collection)) {
final String msg = String.format("Collection %s does not exist", collection);
throw new WebApplicationException(msg, Status.NOT_FOUND)
}
// ...
}
https://www.dropwizard.io/en/stable/manual/core.html#responses
It worked for me by simply registering the custom exception mapper created in the run method of the main class.
environment.jersey().register(new CustomExceptionMapper());
where CustomExceptionMapper can implement ExceptionMapper class like this
public class CustomExceptionMapperimplements ExceptionMapper<Exception>

How to return an error message (String) from a constructor?

Requirements:
Section is created by selecting one teacher, one subject and one
schedule.
System verifies that all business rules are followed.
System detects that a business rule is not being followed.
System informs user of conflict.
System doesn't create new section.
3.System creates new section.
My problem is, if I define a constructor for section, Section(Teacher t, Subject s, Schedule c), I don't know how to return the error message for the conflict.
Should I just let my constructor throw an exception? If yes, how to return a string from a caught exception? How to create that exception?
Or is there any better, yet simple, implementation?
Reporting constructor failure boils down to two options:
Throw an exception as you suggest. This is a reasonable approach if failure is not expected to happen often and is truly "exceptional".
If failure is a normal part of the business logic, I'd recommend using the Factory pattern and returning a wrapper object that contains the newly created object plus a status variable that can indicate the detailed causes of the failure when it occurs.
You can throw the exception for sure.
throw new Exception("Some required files are missing");
Or create a new Exception to be used in your app (it will work the same way)
If you want to read the message inside of a try / catch statement just do this:
try
{
// ...
}
catch(Exception ex)
{
System.out.println(ex.getMessage()); //this will get "Some required files are missing"
}
For more information checke these links out:
http://en.wikibooks.org/wiki/Java_Programming/Throwing_and_Catching_Exceptions
How to throw a general exception in Java?
http://docs.oracle.com/javase/6/docs/api/java/lang/Throwable.html#getMessage()
It isn't possible to return a value from a constructor. Your only way to do this is to throw an exception of some sort. You can either use an existing exception type (if there are any applicable) or create your own by extending Exception. For example:
public class MyException extends Exception {
public MyException(){
super();
}
public MyException(String message){
super(message);
}
}
Your constructor would simply throw a new instance of the exception and set an appropriate message. The code creating the class instance would catch the exception and handle it. You can obtain the message at that point by calling getMessage().

Bad idea to chain exceptions with RMI?

Is it a bad idea to use exception chaining when throwing RemoteExceptions? We have an RMI server that does something like this:
public Object doSomething() throws RemoteException
{
try
{
return getData();
}
catch (CustomException ex)
{
throw new RemoteException(ex);
}
}
I'm getting UnmarshallException caused by a ClassNotFoundException in my client. On the plus side, it turns out that CustomException itself IS exported. Unfortunately, another exception deep inside this guy is NOT exported, which is where the ClassNotFoundException comes in. I think the hierarchy is something like this:
RemoteException -> CustomException -> SQLException -> NotExportedException
The problem I see is that even though we can guarantee that CustomException is exported, we can't guarantee that any lower level exceptions are.
I'm leaning towards NEVER using exception chaining with RemoteExceptions because of this. Instead, I think I should probably log the stack trace on the server side and throw a plain, vanilla RemoteException with no "cause" exception chained to it. Anyone dealt with this situation before?
Rather than wrapping CustomException in RemoteException, you might modify your remote interface like this:
interface Foo extends Remote {
Object doSomething() throws CustomException, RemoteException;
}
The principle here is that only the RMI runtime should be raising RemoteExceptions; they signal some failure in the remoting, not in the application logic. In fact, the concrete implementations don't even need to declare the RemoteException.
But, that doesn't handle the case where your service is catching an exception from some third-party library, but doesn't want to expose that in a throws clause.
public Object doSomething() throws CustomException {
try {
return theirSvc.getData();
} catch (ThirdPartyException ex) {
throw new CustomException("Failed to obtain requested data.");
// or: throw new CustomException("Failed to obtain requested data.", ex) ?
}
}
In this case, I recommend that you not create a "leaky abstraction", where a dependency would be created in a client that would otherwise have no need to know about that third-party library.
Normally, logging and throwing is bad practice, because the same error gets logged repeatedly. But in this case, I think it's justified, since the thrown exception is transported to the client; it may be useful to log it both at the client and server. So the catch block ends up looking like this:
catch (ThirdPartyException ex) {
String message = "Failed to obtain requested data.";
log.error(message, ex);
throw new CustomException(message);
}
This way, the ThirdPartyException dependency is limited to the server, the server logs contain appropriate implementation-specific information, and the error is correctly reported to the client.
We capture the message + entire stack trace from the source exception and passed that on as the remote exception's contents. That way you get all of the stack details, but you don't have to worry about any of ANY of the internal exceptions being non serializable.
You never know what other objects might be inside some other third party (or even your own "first party" custom exceptions!)

Categories