I'm looking for a way to provide multiple pieces of information for exceptions back to end users. The obvious solution of extending Exception ends up with text distributed throughput the code, for example
throw new MyException("Bad data", "The data you entered is incorrect", "http://www.example.com/moreinfo/baddata");
and this quickly becomes unworkable.
I then looked at a catalogue approach but that's too centralized and requires jumping around from one file to another every time an exception is thrown. I'm now considering a hybrid approach with a static ErrorInfoMap class that contains mappings from a key to the more detailed information. Each class then has a static section that contains its own error mappings, so using the class which throws the above exception as an example I'd change it to:
throw new MyException("Bad data");
and at the bottom of the class there would be something like:
static {
ErrorInfoMap.put("Bad data", new ErrorInfo("The data you entered is incorrect", "http://www.example.com/moreinfo/baddata"));
// Information for other exceptions thrown by this class goes here
}
which allows an exception handler to fetch the additional information if required. Is this a good way of solving this issue, or is there a better way to handle this?
I'm not sure what exactly you mean by "the catalog approach" (could you provide a reference or more detailed description?) but from the information you provided, it's not clear to me how a static ErrorInfoMap avoids the problem of being "too centralized and [requiring] jumping around from one file to another every time an exception is thrown".
To me there are several options, depending on exactly what you need to accomplish:
Create a root class, ExceptionTemplate that extends Exception and does whatever repeatable behavior you'd like all your exceptions to do. Formatted toString() methods are a good example. Depending on your exact goals, you might like having your exceptions implement a builder pattern, like so:
throw new BadDataException("Supplied data is not valid")
.expected("a positive integer")
.referenceUrl("http://www.example.com/moreinfo/baddata");
Avoid stringly-typed solutions where an enum or subclass will do. If you don't need to define new exception types at runtime (and if you do, that should be a red flag that there's something deeper wrong with your design) and have an enum that contains all the necessary information to construct your exceptions:
public class EnumException extends Exception {
private EnumException() {} // prevent objects from being instantiated elsewhere
public enum Type {
BAD_DATA("Bad Data","Supplied data is not valid", "http://www.example.com/moreinfo/baddata"),
MISSING_DATA("Missing Data","Required data not found", "http://www.example.com/moreinfo/missingdata");
Type(String title, String genericMessage, String url) {
// Store input
}
public EnumException exception() {
// construct your exception
return new EnumException();
}
}
}
Which can be called with something like:
// note no `new` - the exception is returned by the enum
throw EnumException.Type.BAD_DATA.exception().expected("a positive integer");
This has the advantages of ensuring compile-time type safety, while still giving you the flexibility to define different types of Exceptions in one place.
Create lots of exceptions. I'm still not totally sure what objection you have to just creating a bunch of exceptions. You're looking for ways to "provide additional information" but claim that "the obvious solution of extending Exception ends up with text distributed throughput the code". This shouldn't be the case. Every subclass of Exception should hold all the necessary information except what can only be provided at construction time. Therefore there should be minimal "text distributed throughout the code" as any boiler-plate / reusable strings should be in the Exception class, and nowhere else.
public class DocumentedException extends Exception
{
private String title;
private String genericMessage;
private String detailedMessage;
private String url;
// Generally avoid this long constructor, and define subclasses that only need detailedMessage
public DocumentedException(String t, String g, String d, String u) {
super(g + " - " + d); // sets the getMessage() return value to something sane
title = t;
genericMessage = g;
detailedMessage = d;
url = u;
}
public String toString() {
return title.toUpperCase()+"\n"+
genericMessage+"\n"+
detailedMessage+"\n"+
"More info on this error: "+url+"\n";
}
public static class BadData extends DocumentedException {
public BadData(String details) {
super("Bad Data", "Supplied data is not valid", details, "http://www.example.com/moreinfo/baddata");
}
}
public static class MissingData extends DocumentedException {
public MissingData(String details) {
super("Missing Data", "Required data not found", details, "http://www.example.com/moreinfo/missingdata");
}
}
}
Which you can then call simply with:
throw new DocumentedException.BadData("Username cannot contain whitespace");
Of course, if you expected to need to warn against username errors regularly, you could create an additional class:
public static class BadUsername extends BadData {
public BadUsername() {
super("Usernames can only contain letters, numbers, and underscores");
}
}
The goal, again, is to explicitly define a hierarchy of exceptions that handle all cases you anticipate needing to deal with, such that you avoid repeatedly defining the same strings throughout your application. I personally like the group-exceptions-into-inner-classes pattern I used above, it lets you be very explicit with your errors without creating hundreds of silly stub java files you need to look through constantly. I would say that every major package should have an associated exception-holding class that defines all necessary exceptions for that package.
An alternative to your hybrid approach would be to put the error mapping in the exception itself. When MyException is initialised with Bad data add in the ErrorInfo that you've shown, but also provide a range of constructors for MyException that allows you to override or supplement the default definition of what Bad data means.
You could always have "MyException" as the superclass and have the specific types of errors as subtypes of that. In terms of error messages, you can use static constants on the subtypes to store the different types of errors.
E.g
Exception
-> MyException
-> BadDataException
-> InvalidUserException
etc.
Would be throw like so:
throw new BadDataException(BadDataException.DATA_TOO_LONG);
Related
I'd like to ask something confuses me a lot. Here is the scenario, lets say I have a method preparePayload that takes some argument like messageType, destAddr etc. The duty of method is construct a fully payload (with headers, prefixes etc). Here is the problem, I want to return statusCode (which is enum, like STATUS_OK,STATUS_INVALID_DEST, STATUS_INVALID_MSG_TYPE etc.), and than respect to return status I'd like to implement my logic. But if there is no error (STATUS_OK), I need the prepared payload to move on. So my method should return eighter payload or status code.
In C language, simply sending payload buffer address as an argument to preparePayload method solves the problem perfectly. When the method returns, simply reading payload from the buffer address and moving on the application works. How can I implement this kind of logic in Java?
In addition, preparePayload method is just an example I gave, so the methods I implemented may return String, int[], some class object that I wrote etc. I mean, the type of object that method should return in success case may vary.
Any suggestion will very welcome.
Besides changing to exceptions, there is one more hackish way to allow for "input/output" parameters, like:
public ResultEnum preparePayLoad(List<PayLoad> toPrepare, ... other args) {
...
PayLoad newThing = ...
...
toPrepare.add(newThing);
return someEnum;
}
So, you could use such an approach to "emulate" the "C style"; but the more Java/OO would be
public PayLoad preparePayLoad(args) {
...
PayLoad newThing = ...
...
return newThing;
}
and to throw (checked or unchecked) exceptions for error situations.
The correct idiom in Java is to throw a checked exception (some will say unchecked is better, there is a slight controversy here).
The three important mechanisms you get is:
automatic propagation of error codes up the stack. If you do not handle some type of error in your code (don't check for it), it will get propagated up as an exception - you don't need layered checks (and avoid an error of returning an invalid result, quite common in C),
exceptions work as an "alternate return type", ensuring type safety for both correct results and the error messages (which are full objects - and can contain any number of useful information besides the code)
checked exceptions allow the compiler to check if all the important error statuses are handled in some way.
You can create a class, a wrapper, for example:
public class Result {
public enum Status {
STATUS_OK, STATUS_INVALID_DEST, STATUS_INVALID_MSG_TYPE
}
Status status;
String payload;
}
that will be returned by your method preparePayload. Then, when you call your method, you can do it like this:
Result result = preparePayload(args);
//better will be a switch with case for each possible status
if (result.state == Result.State.STATUS_OK)
//do what you want with payload
System.out.println(result.payload);
else
return;
I want to design an API which reads a large text file, extracts the relevant info and returns a list of Foo objects like this:
interface FooService {
Optional<Foo> getFoo(Bar bar);
}
The format of the text file and the way it is parsed is always the same. The only thing that can vary is the location of the file, i.e. it could be a file on the local system or an URL. So I created an AbstractFooService:
class AbstractFooService implements FooService {
Map<Bar, Foo> registry;
AbstractFooService(InputStream is) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
registry = reader.lines()
.map(l -> l.split(';'))
.map(a -> new Foo(a[0]), a[1]))
.collect(Collectors.groupingBy(...));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
Optional<Foo> getFoo(Bar bar) {
return Optional.ofNullable(registry.get(bar));
}
}
Concrete implementations would just call the super constructor with an InputStream:
class UrlFooService extends AbstractFooService {
UrlFooService(String url) {
super(createStream(url));
}
private static InputStream createStream(final String url) {
try {
return new URL(string).openStream();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
Is that a sound API design or is there a 'better' way to achieve my goal? I.e. is it smart to call the super constructor with an InputStream or would it be better to have a separate load() method that opens the stream when needed?
I don't see why you need that abstract base class there. Preferring composition over inheritance; I think the more reasonable solution would be to have:
public class FooServiceImpl implements FooService {
...
And then clients such as
public class UrlFooService implements FooService {
private final FooService delegatee;
public UrlFooService(URL url) {
delegate = new FooServiceImpl(url.openStream())
...
#Override
Optional<Foo> getFoo(Bar bar) { return delegatee.getFoo(bar); }
Inheritance couples your concrete service classes with that parent class; I would prefer to avoid, by using this simple "delegatee" mechanism.
Please note: I also changed the ctor of the UrlSerivce to take a URL. You already have the types there, so why bother to call new yourself? That just means that your UrlService would have to deal with all the things that could go wrong there!
There's a couple of challenges with your question here and I would start by breaking down the problem a little differently.
As #sisyphus said, watch out for those things you're doing in the constructor. A constructor really should be focused on just creating a "valid object" and nothing more. Many good ideas from #GhostCat too.
Instead think of modeling the problem as follows:
Create an interface that represents the API for your service. In this case if you want it to be "getFoo()" then great. Consider what you would want to pass (is it really the file or a URL or path). Since you said it was a big file, it might not be a great idea to instantiate a big object in memory that you're going to be parsing again into a useful format. You'll definitely pay the price in garbage collection.
Next you should think of separating out the "finding" of the file - or opening the stream with the parsing logic. There are plenty of exceptions that can occur when simply trying to open the file - from it not being found, to not having permissions, to having too many open files (ulimit).
When it comes to parsing, I would suggest that you consider to get really clear on what you are parsing and for what. If this is a real-world problem, 'stable formats' are always subject to change - especially when it comes to tolerating 'invalid' formats - like the existence of other non-printable characters or an unexpected EOF. There will be a lot of demands to handle things gracefully and also a need to understand the stats of what was parsed, what had errors and how to handle that.
My 2 cents.
I am trying to intercept an Exception thrown by my algorithm in Java, and change the text to another language, and show it to the user. Is this possible in java?
Sorry by my English.
You can catch an exception, and then throw a new one of the same type (or a different type if you prefer). Then translate the message from the original exception and pass it into the new exception. Something like the following (not tested):
try {
// do something
}
catch (Exception e) {
throw new Exception(translate(e.getMessage()))
}
public String translate(String message) { /* translation code */ }
Update in response to comment:
If you can modify the application (and particularly if the application uses custom exceptions derived from a few base classes) then you might be able to modify these to retrieve translated messages (but if you could do that, you could build in the translated messages, or full internationalisation, from the start!).
Intercepting and replacing all Exceptions globally is probably not possible, although it looks like you can at least detect them globally using debug hooks - see this answer. It's conceivable that you could modify the Exception message on-the-fly using reflection, but this sounds pretty nasty.
One final possibility is to use Aspect-Oriented Programming (AOP) to compile-in extra behaviour around code that throws an exception (see this question, for example). You'd need to recompile the whole application using AOP tools though, and would probably still need to modify the application code a bit.
I think you want Thread.setDefaultUncaughtExceptionHandler()
This issue had more details if you need them...
swing uncaughtexceptionhandler
You would need to translate the message text of an exception only if your were reporting the message text of exceptions. But doing that is a mistake.
The message was created when the exception was thrown. It therefore at best can provide only very low level information, which can be inappropriate for reporting to a user.
Philosophically, using the message is against the whole point of exceptions, which is to separate the detection and initiation of error handling (the throw part) from completion of handling and reporting (the catch part). Using the message means the message must be good for reporting, which moves responsibility for reporting to the location that should be responsible for only detection and initiation. That is, I'd argue that the getMessage() part of the design of Throwable was a mistake.
Instead of doing that, follow the advice to choose what message to report to the user at the point where your catch the exception. You can internationalize that message use the usual Java text internationalization facilities.
I solved my question with this solution
public class ParamsException extends RuntimeException {
private static final long serialVersionUID = 7161500238672497882L;
public ParamsException() {
super();
}
public ParamsException(String message) {
super(new BaseResourcesBusiness().getException(message));
}
public ParamsException(Throwable cause) {
super(cause);
}
public ParamsException(String message, Throwable cause) {
super(new BaseResourcesBusiness().getException(message), cause);
}
}
the BaseResourceBusiness.getException(message) get the message from a XML or Database to a specific language. So all my exception is created in this mode
public static final class NotFoundInDatabaseException extends ParamsException {
private static final long serialVersionUID = -1595240938885629473L;
public NotFoundInDatabaseException () {
super("Not found in database");
}
}
in the code im using with this mode throw new NotFoundInDatabaseException ()
I had difficulties finding a relevant title since it is not a simple issue. I will try to explain. I have a class responsible of error reporting whose methods basically wrap multiple ways of reporting an error.
For example, I have a method failTest:
public static void failTest(Logger log, Exception e, String message, boolean reportToES, String esTestPath, String esTestSet, String esTestInstance)
{
log.error(e, message);
someExternalErrorReportingService(reportToES, esTestPath,esTestSet,esTestInstance);
Assert.fail(e,message);
}
And I call this error reporting method in many, many places and it doesn't seem a good practice (too many parameters, hard to follow their order etc.) to just call it with the es* parameters each and every time because they don't change very often so they could be set up once and then reused.
And I came up with this version
public static void failTest(Logger log, Exception e, String message)
{//same body
}
And then added method to set up es* parameters
setES(boolean reportToES, String esTestPath, String esTestSet, String esTestInstance)
{
this.reportToES = reportToES;
this.esTestPath = esTestPath;
this.esTestSet = esTestSet;
this.esTestInstance=esTestInstance;
}
and of course added these instance variables above.
And only now I can enunciate the issue:
now if I want to use this error reporting class I need to first instantiate it and set the es* fields. The issue is that I often need to use the error reporting in a utility class that could be static but now, with my change above, I have to instantiate it and set up the error reporting class in order to have the es* fields set before I call failTest().
To conclude, I don't like this solution either because I can't use static utility classes anymore and moreover some utility classes are already used in a static way so cannot be refactored to non-static and will end up being used sometimes static, sometimes instantiated.
So the question is, do you see a better solution in order to simplify the calling of failTest() in utility classes?
To give you an example, we have a client that
sets up the error reporting class and sets up its es* fields
This client calls utility method Utility.doSomething
public static doSomething(reportToES, esTestPath, esTestSet, esTestInstance)
{
try{
methodThatThrowsFatalException()
}
catch(Exception e){
failTest(log, e, "Some smart message",reportToES, esTestPath, esTestSet, esTestInstance);
}
}
Now, in order to reduce the number of parameters we can just add setErrorReportingInstance to the Utility class,
then in client instantiate the Utility, then utilityInstance. setErrorReportingInstance(configuredErrorReportingInstance). And doSomething becomes:
public static doSomethingRefactored()
{
try{
methodThatThrowsFatalException()
}
catch(Exception e){
errorReportingInstance.failTest(log, e, "Some smart message");
}
}
What is not ok, from my point of view, is that:
1. I have complicated the usage of Utility. Now I have to make sure it is instantiated before I use it. It's inconvenient when having a lot of Utility like classes.
2. I cannot make static methods in Utility if I have to do error reporting in their implementation.
3. The methods that are already used as static will remain with the es* parameters in their signature (due to backward compatibility). So I will have in the same class methods like doSomething and also methods like doSomethingRefactored.
4. I have created a dependency between utility classes and error reporting so I have an issue when I need to test the utility methods
The question is, how can I keep the simple design of utility classes as simple collection of static utility methods but in the same time use the error reporting class but without passing too many parameters since it is bad practice?
More details:
Actually the client is many TestNG test cases:
So first I had :
class TestClass1
{
static final boolean REPORT_TO_ES="true",
static final String ES_TEST_PATH="somePath", //and so on for the others
#Test
{
Utility1.doSomething(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,...
Utility2.doSomethingElse(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,...
Utility3.doSomethingMoreUseful(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,...
Utility4.doSomethingSomething(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,...
}
And then I would try to get rid of calling the doSomethings with the ES* values
by setting them once on the ErrorReporter instance (so I would also make ErrorReporter non-static).
class TestClass1
{
private ErrorReporter errorReporter = new ErrorReporter();
errorReporter.setReportToEs(true);
errorReporter.setEsTestPath("somePath");//and so on
Utility1 utility1Instance = new Utility1();
utility1Instance.setErrorReporter(errorReporter);
Utility2 utility1Instance = new Utility2();
utility2Instance.setErrorReporter(errorReporter);
#Test
{
utility1Instance.doSomething();
utility2Instance.doSomethingElse();
...
The title to your question should be "Static Mess".
Take a look at how real loggers work and you may get some ideas. Log4J and Slf4j are well respected ones. You need to control all of your static variables. You could create a Logger class that encapsulates the ES data and does the real work of logging:
// Does the real work of logging.
class Logger {
public Logger(all of your es data)
public fail(String msg) // Logs msg
}
Then you need a static collection of these Loggers referenced by name (I assume you have more than one set of es data). This gives you a central place to go get the loggers. Works if you're in a static method or somewhere else. The static collection goes inside the LogFactory object
class LogFactory {
private static Map<String, Logger> loggers ...
public static Logger get(String name) ...
}
Here is your static method using the new logger:
public static doSomething() {
try {
methodThatThrowsFatalException()
}
catch(Exception e){
LogFactory.get("Util").failTest(e, "Some smart message");
}
}
I would add a clear or reset method to LogFactory so that you have a chance of writing JUnit tests for your code. For the same reason I would write a NullLogger (in which case you might want to pull out an interface that the NullLogger and the EsLogger can both implement.
You need to decide how to add Loggers to LogFactory. I suggest doing it in your main class. Resist the temptation to do it in a static initializer.
LogFactory could also be written so it holds a collection and not a static collection. You then just keep a static reference (a Singleton) to it. Just keep in mind that you'll want a way to clear the Singleton to make unit testing possible.
Good luck.
Suppose i want to read the following file:
TestFile;100
into the fields of the class:
public class MyReader {
String field1;
Integer field2;
}
There are two slightly different ways to read the content:
public class MyReader {
public void loadValues(File file) throws IOException {
//a generic method that reads the content file to a string throwing an IOException
String line = readFileToString(file);
String[] values = line.split(";");
field1=values[0];
field2=Integer.parseInt(values[1]);
}
//then i'll have well known getters:
public String getField1() {
return field1;
}
public Integer getField2() {
return field2;
}
Now the second idiom:
private String[] values; //made the values a class field
public void loadValues(File file) throws IOException {
//a generic method that reads the content file to a string throwing an IOException
String line = readFileToString(file);
values = line.split(";");
}
public String getField1() {
return values[0]
}
public Integer getField2() {
return Integer.parseInt(values[1]);
}
the big difference is in exception management.
I deliberately omitted to catch two runtime exceptions that may happen in both cases:
ArrayIndexOutOfBoundsException if the file contains less than two fields
NumberFormatException if the Integer parsing fails
First approach
All fields are loaded at startup. Sufficient that one of them is not parsable, i get the NumberFormatException. If there are less fields than the required i'll get the out of bounds exception. That sounds good, expecially if i want to ensure the correctness of all the field values behind the fact that i will use a specific one: fail fast paradigm.
Suppose that i have one hundred fields, that the record contains an error that in turn is logged to a file for troubleshooting. As is, this code gives something like this:
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
that is: i get the error, the value that caused the error, the line number that gives the error, but NOT the field name. Good for the developer, not so good for the system engeneer that normally has not access to the source code.
Second approach
The fields are "extracted" and parsed from the data string only when they are accessed through getters.
Each getter may return the two errors described above, in the very same circumstances.
There is a certain degree of "fault tolerance" as opposed to "fail fast paradigm". If the 100th field of the record contains an incorrect value, but the client of the class doesn't call for its getter, the exception will never be thrown.
On the other hand, when the getter of a incorrect value is called, the logged exception will contain the information of which field caused the problem (in the stack trace):
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:449)
at java.lang.Integer.parseInt(Integer.java:499)
at com.test.MyReader.getField2(MyReader.java:39)
at com.test.MyReader.test(MyReader.java:33)
at com.test.MyReader.main(MyReader.java:16)
Question(s)
Both approaches has pros and cons, and one can say that the decision on which one adopt is context-dependent. The questions are:
getters and setters are a javabeans subject. is it "acceptable" that they return exceptions?
the class in the two approaches may apparently have the same interface, but since they have a completely different architecutre of exception, the client is supposed to use them in a completely different way. So how to rapresent this fact to the client? Maybe the getters semantic is misleading, perhaps there is a more eloquent way?
First of all the second approach won't work as you store the values[] array as local variable and it won't be accessible to other functions (getters in your case).
Second don't throw the exceptions in your getters as you api you expose will be misleading and won't conform to any convention.
Third, instead of parsing the string yourself, consider using a ready to use library for csv parsing and don't reinvent the wheel, eg. http://opencsv.sourceforge.net/
Fourth, create a simple POJO object for the csv records, you can check for erros while assigning the values to each fields and then throw the exception or not, provide default values etc.
Hope that helps