Parse JSON without succession of Try-Catch blocks - java

I would like to parse a JSON, but every time I get a value, I have to put the instruction in a try-catch block. Here is an example:
try {
this.setID(jsonObject.getLong("id"));
} catch (JSONException e) {
}
try {
this.setName(jsonObject.getString("name"));
} catch (JSONException e) {
}
//and so on....
I don't care if an instruction arise an exception. So I was wondering if it is possible to delete all the try-catch blocks and put the instructions all together.
Actually it is more a java problem and not only an android problem....
EDIT
Just clarifying what is the problem.
When an exception arises because there is not the tag I was looking for, I would continue with the next tag check instead of handling the exception. To do this, I have to write the code as I posted above, thus a succession of try-catch blocks. I was looking for a faster (and more elegant) solution.

You can use the opt methods instead of the get methods, assuming that it's okay for the keys not to exist. If the keys are not optional, and your app cannot recover from those fields not all existing, you should definitely use the get methods and fail fast if you run into an error.
Another helpful method you can use is the has() method. This checks if there is a mapping for a given key. (e.g. if (json.has("id") id = json.optString("id"))).

Maybe I didn't understand what you're asking, but why don't you put all calls to jsonObject within the same try-catch block?
try {
this.setID(jsonObject.getLong("id"));
this.setName(jsonObject.getString("name"));
} catch (JSONException e) {
// log or consume it some other way
}
You should never just swallow exceptions. At least log an error.

Like #Sotirios was saying you can't disregard a json exception.
You can put all your json reading in a method and make that method throw the JSONException, like this:
public void readJson(String json) throws JSONException{
this.setID(jsonObject.getLong("id"));
this.setName(jsonObject.getString("name"));
}
but you steel have to do a try catch when you call that method:
try {
readJson(jLine);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

I think it is more of a library problem than anything else. A couple of JSON libraries in Java tend to add exceptions in their library calls as if the designer wanted to use invasive C-like error status codes but with the added weight of Java exceptions syntax. I can partially understand the motives for such an interface, but it looks really inelegant.
I would suggest using json-simple, which is too simple sometimes but gets the job done and stays out of the way.

Replace
jsonObject.getFoo("key")
with
jsonObject.optFoo("key")
If the key is not found, a null or similar default value is returned instead of an exception being thrown.

If you want cleaner syntax, you should look at gson. If you know what the json will look like, nothing beats it.
If your JSON looks like this:
{
"id": 432942039,
"name": "My name",
"values": [0, 1, 2, 3]
}
You'd create a POJO class that looks like this:
public class MyClass {
public MyClass() {}
private long id;
private String name;
private int[] values;
}
And parse it like this:
private parse(String jsonString) {
Gson gson = new Gson();
MyClass myObject = gson.fromJson(jsonString, MyClass.class);
}
And that's it. No setters are needed; it uses reflection to match the fields. No annotations. No errors if there are fields in your JSON string that don't match anything in your POJO and vice versa.

Related

How can I collect results of a Java stream operation that throws exceptions in a concise manner?

Have a look at the following snippet that tries to convert a list of strings into a list of class objects:
public static List<Class<?>> f1(String... strings) {
return
Stream.of(strings)
.map(s -> {
try {
return Class.forName(s);
}
catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
return null;
})
.collect(Collectors.toList());
}
Because of the way Java handles checked exceptions in streams (as has been discussed at length here - where I also blatantly stole my example snippet from), you have to have the additional return statement after the try-catch block. This will result in an unwanted null reference being added to the result of type List<Class>.
To avoid this extra null reference, I came up with the following function, achieving a better result with a plain old procedural loop:
public static List<Class<?>> f2(String... strings) {
List<Class<?>> classes = new ArrayList<>();
for (String s : strings) {
try {
classes.add(Class.forName(s));
}
catch (ClassNotFoundException e) {
// Handle exception here
}
}
return classes;
}
Does this observation allow me to draw a conclusion in the form of a best-practice advice, that could be expressed like the following?
If you need to call a function that throws an exception inside a stream and you cannot make use of stream.parallel(), better use a loop, because:
You'll need the try-catch block anyway (notwithstanding the tricky solutions involving some kind of wrapper around the throwing function provided in the aforementioned discussion)
Your code will not be less concise (mainly because of 1.)
Your loop will not break in case of an exception
What do you think?
You can do this without introducing elements which you have to filter in a subsequent step:
public static List<Class<?>> f1(String... strings) {
return Arrays.stream(strings)
.flatMap(s -> {
try { return Stream.of(Class.forName(s)); }
catch(ClassNotFoundException e) { return null; }
})
.collect(Collectors.toList());
}
Still, this isn’t more concise than a loop solution.
But it should be noted that this has nothing to do with checked exceptions. You want to continue in the exceptional case, omitting the failed element. That always requires you to catch the exception to implement this alternative behavior (the default would be to propagate the exception to the caller), whether the exception is checked or unchecked. The checked case has the advantage of reminding you that you have to do this.
In other words, the Stream API does not allow you to implement the behavior of propagating checked exceptions to the caller in a simple way, but that’s not what you want here anyway. If Class.forName(String) was designed to throw unchecked exceptions only, omitting the try … catch block in map would cause the entire operation to abort in the exceptional case by relaying the exception to the caller. But, as said, that’s not what you want here.
As #Patrick wrote, you could filter your null classes. Just add a filter after the map in your stream:
.filter(Objects::nonNull)
.collect(Collectors.toList());

How to ignore Exceptions in Java

I have the following code:
TestClass test=new TestClass();
test.setSomething1(0); //could, but probably won't throw Exception
test.setSomething2(0); //could, but probably won't throw Exception
I would like to execute: test.setSomething2(0); even if test.setSomething(0) (the line above it) throws an exception. Is there a way to do this OTHER than:
try{
test.setSomething1(0);
}catch(Exception e){
//ignore
}
try{
test.setSomething2(0);
}catch(Exception e){
//ignore
}
I have a lot of test.setSomething's in a row and all of them could throw Exceptions. If they do, I just want to skip that line and move to the next one.
For clarification, I don't care if it throws an Exception, and I can't edit the source code of the code which throws this exception.
THIS IS A CASE WHERE I DON'T CARE ABOUT THE EXCEPTIONS (please don't use universally quantified statements like "you should never ignore Exceptions"). I am setting the values of some Object. When I present the values to a user, I do null checks anyway, so it doesn't actually matter if any of the lines of code execute.
try {
// Your code...
} catch (Exception ignore) { }
Use the word ignore after the Exception keyword.
There is no way to fundamentally ignore a thrown exception. The best that you can do is minimize the boilerplate you need to wrap the exception-throwing code in.
If you are on Java 8, you can use this:
public static void ignoringExc(RunnableExc r) {
try { r.run(); } catch (Exception e) { }
}
#FunctionalInterface public interface RunnableExc { void run() throws Exception; }
Then, and implying static imports, your code becomes
ignoringExc(() -> test.setSomething1(0));
ignoringExc(() -> test.setSomething2(0));
IntelliJ Idea IDE suggests to rename a variable to ignored
when it isn't used.
This is my sample code.
try {
messageText = rs.getString("msg");
errorCode = rs.getInt("error_code");
} catch (SQLException ignored) { }
Unfortunately no, there isn't, and this is by intention. When used correctly, exceptions should not be ignored as they indicate that something didn't work and that you probably shouldn't continue down your normal execution path. Completely ignoring exceptions is an example of the 'Sweep it under the rug' anti-pattern, which is why the language doesn't support doing so easily.
Perhaps you should look at why TestClass.setSomething is throwing exceptions. Is whatever you're trying to 'test' really going to be valid if a bunch of setter methods didn't work correctly?
You can't ignore exception in Java. If a method declares being able to throw something this is because something important can't be done, and the error can't be corrected by the method designer. So if you really wan't to simplify your life encapsulate the method call in some other method like this :
class MyExceptionFreeClass {
public static void setSomething1(TestClass t,int v) {
try {
t.setSomething1(v);
} catch (Exception e) {}
public static void setSomething2(TestClass t,int v) {
try {
t.setSomething2(v);
} catch (Exception e) {}
}
and call it when you need it:
TestClass test=new TestClass();
MyExceptionFreeClass.setSomething1(test,0);
MyExceptionFreeClass.setSomething2(test,0);
You should not ignore Exceptions. You should handle them. If you want to make your test code simple, then add the try-catch block into your functions. The greatest way to ignore exceptions is to prevent them by proper coding.
I know this is old, but I do think there are occasions when you want to ignore an exception. Consider you have a string that contains a delimited set of parts to be parsed. But, this string can sometimes contain say, 6 or 7 or 8 parts. I don't feel that checking the len each time in order to establish an element exists in the array is as straight forward as simply catching the exception and going on. For example, I have a string delimited by '/' character that I want to break apart:
public String processLine(String inLine) {
partsArray = inLine.split("/");
//For brevity, imagine lines here that initialize
//String elems[0-7] = "";
//Now, parts array may contains 6, 7, or 8 elements
//But if less than 8, will throw the exception
try {
elem0 = partsArray[0];
elem1 = partsArray[1];
elem2 = partsArray[2];
elem3 = partsArray[3];
elem4 = partsArray[4];
elem5 = partsArray[5];
elem6 = partsArray[6];
elem7 = partsArray[7];
catch (ArrayIndexOutOfBoundsException ignored) { }
//Just to complete the example, we'll append all the values
//and any values that didn't have parts will still be
//the value we initialized it to, in this case a space.
sb.append(elem0).append(elem1).append(elem2)...append(elem7);
//and return our string of 6, 7, or 8 parts
//And YES, obviously, this is returning pretty much
//the same string, minus the delimiter.
//You would likely do things to those elem values
//and then return the string in a more formatted way.
//But was just to put out an example where
//you really might want to ignore the exception
return sb.toString();
}
Those who write empty catch blocks shall burn in the Hell for the eternity.
Or worse, they will be forced to debug the damn rubbish they wrote forever and ever.
That said, one thing you might want to do is writing exception handling in a less verbose way. The NoException library is very good at that.

String inside dot operators

I'm pretty sure this is impossible (considering it is such abysmal programming practice), but I'm going to ask anyway.
In Java, is there a way to use a string in place of a method name (or something else) using the dot operator?
For example: java.stringname.NumericShaper(); where stringname = "awt.font"
I'm trying to put some repetitive code into an iterative loop. For example, one of my variables is "Settings.can1.baud", and I want to iterate the "can1" part each time I go through the loop. Perhaps there's a better way to do this?
I'm new to Java programming, so I'm not sure that made any sense...
If you mean you have a bunch of members called can1, can2, can3, etc., then you should use an array or a collection instead.
It is possible to do what you want using reflection. But it's fiddly, bad practice (often), and unnecessary in this case.
You could do this using reflection:
try {
//loop over stringnames?
String stringname = "awt.font";
Class<?> numericShaperClass = Class.forName("java." + stringname + ".NumericShaper");
NumericShaper numericShaper = (NumericShaper) numericShaperClass.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
As for the second part of your question, you can access the member variables of your Properties class using the Class.getField() method.
Using reflection might be overkill in this situation and can result in some pretty unreadable, and possibly slow code.

Is it ok to handle a class metadata through reflection to ensure a DRY approach?

The title might seem unsettling, but let me explain.
I'm facing an interesting challenge, where I have a hierarchy of classes that have associated an object that stores metadata related to each one of its attributes (an int-valued enum with edit flags like UPDATED or NO_UPDATE).
The problem comes when merging two objects, because I dont want to check EVERY field on a class to see if it was updated and skip or apply the changes.
My idea: Reflection.
All the objects are behind an interface, so I could use IObject.class.getMethods() and iterate over that array in this fashion:
IClass class = //Instance of the first class;
IAnotherClass anotherClass = //Instance of the second class;
for(Method m : IObject.class.getMethods()) {
if(m.getName().startsWith("get")) {
try {
//Under this method (which is a getter) I cast it on
//both classes who implement interfaces that extend an
//interface that defines the getters to make them
//consistent and ensure I'll invoke the same methods.
String propertyClass = (String)m.invoke(class);
String propertyAnotherClass = (String)m.invoke(anotherClass);
if(propertyClass != propertyAnotherClass) {
//Update attribute and attribute status.
}
} catch (Exception e) {
}
}
}
Is there another way to implement this or should I stick to lengthy methods invoking attribute per attribute and doing the checks like that?. The objects are not going to change that much and the architecture is quite modular, so there is not much update involved if the fields change but having to change a method like that worries me a little.
EDIT 1: I'm posting a working code of what I have got so far. This code is a solution for me but, tough it works, I'm using it as a last resource not because I have time to spend but because I don't want to rediscover the wheel. If I use it, I'll make a static list with the methods so I only have to fetch that list once, considering the fact that AlexR pointed out.
private static void merge(IClazz from, IClazz to) {
Method methods[] = from.getClass().getDeclaredMethods();
for(Method m : methods) {
if(m.getName().startsWith("get") && !m.getName().equals("getMetadata")) {
try {
String commonMethodAnchor = m.getName().split("get")[1];
if(!m.getReturnType().cast(m.invoke(from)).equals(m.getReturnType().cast(m.invoke(to)))) {
String setterMethodName = "set" + commonMethodAnchor;
Method setter = IClazz.class.getDeclaredMethod(setterMethodName, m.getReturnType());
setter.invoke(to, m.getReturnType().cast(m.invoke(from)));
//Updating metadata
String metadataMethodName = "set" + commonMethodAnchor + "Status";
Method metadataUpdater = IClazzMetadata.class.getDeclaredMethod(metadataMethodName, int.class);
metadataUpdater.invoke(to.getMetadata(), 1);
}
} catch (Exception e) {
}
}
}
}
metadataUpdater sets the value to 1 just to simulate the "UPDATED" flag I'm using on the real case scenario.
EDIT 3: Thanks Juan, David and AlexR for your suggestions and directions! They really pointed me to consider things I did not consider at first (I'm upvoting all your answers because all of them helped me).
After adding what AlexR sugegsted and checking jDTO and Apache Commons (finding out that in the end the general concepts are quite similar) I've decided to stick to my code instead of using other tools, since it is working given the object hierarchy and metadata structure of the solution and there are no exceptions popping up so far. The code is the one on the 2nd edit and I've placed it on a helper class that did the trick in the end.
Apache Commons Bean Utils may resolve your problem: http://commons.apache.org/beanutils/
If you want to copy all properties, try to use copyProperties: http://commons.apache.org/beanutils/v1.8.3/apidocs/src-html/org/apache/commons/beanutils/BeanUtils.html#line.134
Look an example from: http://www.avajava.com/tutorials/lessons/how-do-i-copy-properties-from-one-bean-to-another.html
FromBean fromBean = new FromBean("fromBean", "fromBeanAProp", "fromBeanBProp");
ToBean toBean = new ToBean("toBean", "toBeanBProp", "toBeanCProp");
System.out.println(ToStringBuilder.reflectionToString(fromBean));
System.out.println(ToStringBuilder.reflectionToString(toBean));
try {
System.out.println("Copying properties from fromBean to toBean");
BeanUtils.copyProperties(toBean, fromBean);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println(ToStringBuilder.reflectionToString(fromBean));
System.out.println(ToStringBuilder.reflectionToString(toBean));
I think the best approach would be using proxy objects, either dynamic proxies or cglib enhancers or something like it, so you decorate the getters and setters and you can keep track of the changes there.
Hope it helps.
Your approach is OK, but keep in mind that getMethod() is much slower than invoke(), so if your code is performance critical you will probably want to cache the Method objects.

What is a good way to pass useful state information to an exception in Java?

I noticed some confusion initially with my question. I'm not asking about how to configure a logger nor how to use a logger properly, but rather how to capture all of the information that would have been logged at a lower logging level than what the current logging level is in the exception message.
I have been noticing two patterns in Java for logging information that may be useful to a developer when an exception occurs.
The following pattern seems very common. Basically, you just have your logger log information in-line as needed, so that when an exception occurs you have the log trace.
try {
String myValue = someObject.getValue();
logger.debug("Value: {}", myValue);
doSomething(myValue);
}
catch (BadThingsHappenException bthe) {
// consider this a RuntimeException wrapper class
throw new UnhandledException(bthe);
}
The drawback with the above approach is that if your users require relatively quiet logs and need a high level of reliability to the point where they just can't "try it again in debug mode", the exception message contains insufficient data by itself to be useful to the developer.
The next pattern is one that I have seen that tries to mitigate this problem but seems ugly:
String myValue = null;
try {
myValue = someObject.getValue();
doSomething(myValue);
}
catch (BadThingsHappenException bthe) {
String pattern = "An error occurred when setting value. [value={}]";
// note that the format method below doesn't barf on nulls
String detail = MessageFormatter.format(pattern, myValue);
// consider this a RuntimeException wrapper class
throw new UnhandledException(detail, bthe);
}
The above pattern seems to somewhat solve the problem, however, I'm not sure I like to declare so many variables outside the scope of the try block. Especially, when I have to deal with very complicated states.
The only other approach I have seen is using a Map to store key-value pairs that are then dumped into the exception message. I'm not sure I like that approach either since it seems to create code bloat.
Is there some Java voodoo out there that I am missing? How do you handle your exception state information?
We tend to create our most important application specific runtime exception classes with some special constructors, some constants and a ResourceBundle.
Example snippet:
public class MyException extends RuntimeException
{
private static final long serialVersionUID = 5224152764776895846L;
private static final ResourceBundle MESSAGES;
static
{
MESSAGES = ResourceBundle.getBundle("....MyExceptionMessages");
}
public static final String NO_CODE = "unknown";
public static final String PROBLEMCODEONE = "problemCodeOne";
public static final String PROBLEMCODETWO = "problemCodeTwo";
// ... some more self-descriptive problem code constants
private String errorCode = NO_CODE;
private Object[] parameters = null;
// Define some constructors
public MyException(String errorCode)
{
super();
this.errorCode = errorCode;
}
public MyException(String errorCode, Object[] parameters)
{
this.errorCode = errorCode;
this.parameters = parameters;
}
public MyException(String errorCode, Throwable cause)
{
super(cause);
this.errorCode = errorCode;
}
public MyException(String errorCode, Object[] parameters, Throwable cause)
{
super(cause);
this.errorCode = errorCode;
this.parameters = parameters;
}
#Override
public String getLocalizedMessage()
{
if (NO_CODE.equals(errorCode))
{
return super.getLocalizedMessage();
}
String msg = MESSAGES.getString(errorCode);
if(parameters == null)
{
return msg;
}
return MessageFormat.format(msg, parameters);
}
}
In the properties file we specify the exception descriptions, e.g.:
problemCodeOne=Simple exception message
problemCodeTwo=Parameterized exception message for {0} value
Using this approach
We can use quite readable and understandable throw clauses (throw new MyException(MyException.PROBLEMCODETWO, new Object[] {parameter}, bthe))
The exception messages are "centralized", can easily maintained and "internationalized"
EDIT: change getMessage to getLocalizedMessage as Elijah suggested.
EDIT2: Forgot to mention: this approach does not support Locale changing "on-the-fly" but it is intentional (it can be implemented if you need it).
Another good logging API is SLF4J. It can be configured to also intercept log APIs for Log4J, Java Util Logging, and Jakarta Commons Logging. And it can also be configured to use various logging implementations, including Log4J, Logback, Java Util Logging, and one or two others. This gives it enormous flexibility. It was developed by the author of Log4J to be its successor.
Of relevance to this question, the SLF4J API has a mechanism to concatenate string valued expressions into a log message. The following calls are equivalent, but the second is about 30x faster to process if you're not outputting debug level messages, since the concatenation is avoided:
logger.debug("The new entry is " + entry + ".");
logger.debug("The new entry is {}.", entry);
There's a two argument version too:
logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);
And for more than two you can pass in an array of Object like this:
logger.debug("Value {} was inserted between {} and {}.",
new Object[] {newVal, below, above});
This is a nice terse format that eliminates clutter.
Example source is from the SLF4J FAQ.
Edit: Here's a possible refactoring of your example:
try {
doSomething(someObject.getValue());
}
catch (BadThingsHappenException bthe) {
throw new UnhandledException(
MessageFormatter.format("An error occurred when setting value. [value={}]",
someObject.getValue()),
bthe);
}
Or if this pattern occurs more than a few places you could write a set of static methods that capture the commonality, something like:
try {
doSomething(someObject.getValue());
}
catch (BadThingsHappenException bthe) {
throwFormattedException(logger, bthe,
"An error occurred when setting value. [value={}]",
someObject.getValue()));
}
and of course the method would also put the formatted message out on the logger for you.
Perhaps I'm missing something, but if the users really require a relatively quiet log file, why don't you just configure your debug logs to go to a separate spot?
If that's insufficient, then capture a fixed amount of the debug logs in RAM. E.g., the last 500 entries. Then, when something ugly happens, dump the debug logs along with the problem report. You don't mention your logging framework, but this would be pretty easy to do in Log4J.
Even better, assuming you have the user's permission, just send an automatic error report rather than logging. I recently helped some folks run down a hard-to-find bug and made the error reporting automatic. We got 50x the number of bug reports, making the problem pretty easy to find.
Take a look at the MemoryHandler class from java.util.logging. It acts as a buffer between your log.$level() invocations and the actual output, and will pass it's buffer content into the output only if some condition is met.
For example you could configure it to dump content only if it sees ERROR level message. Then you can safely output DEBUG level messages and no one will see them unless actual error occurs and then all messages are written to log file.
I would guess there are similar implementations for other logging frameworks.
EDIT: One possible issue with this approach is a performance lost on generating all the debug messages (see #djna comment). Because of this it could be a good idea to make the level of logging going into the buffer configurable - in production it should be INFO or higher, and only if you are actively hunting a problem down it could be turned down to DEBUG.
Besides your example which declares local fields outside the try block in order to be accessible inside the catch block, one very simple way of handling this is to dump the state of the class out in the Exception using the class's overridden toString method. Granted, this is only useful in Classes that maintain state.
try {
setMyValue(someObject.getValue());
doSomething(getMyValue());
}
catch (BadThingsHappenException bthe) {
// consider this a RuntimeException wrapper class
throw new UnhandledException(toString(), bthe);
}
Your toString() would need to be overridden:
public String toString() {
return super.toString() + "[myValue: " + getMyValue() +"]";
}
edit:
another idea:
You could maintain state in a ThreadLocal debug context. Suppose you create a class called MyDebugUtils which holds a ThreadLocal that contains a Map per Thread. You allow for static access to this ThreadLocal and maintenance methods (ie, to clear the context when your debugging is finished).
The interface could be:
public static void setValue(Object key, Object value)
public static void clearContext()
public static String getContextString()
and in our example:
try {
MyDebugUtils.setValue("someObeject.value", someObject.getValue());
doSomething(someObject.getValue());
} catch (BadThingsHappenException bthe) {
// consider this a RuntimeException wrapper class
throw new UnhandledException(MyDebugUtils.getContextString(), bthe);
} finally {
MyDebugUtils.clearContext();
}
There might be some issues that you would want to iron out, such as handling cases where your doSomething method also contains a try/catch/finally set that clears the debug context. This could be handled by allowing for finer granularity in the context Map than just the Thread in the process:
public static void setValue(Object contextID, Object key, Object value)
public static void clearContext(Object contextID)
public static String getContextString(Object contextID)
One option that no one seems to have mentioned yet is to use a logger that logs to an in memory buffer, and only pushes the information into the actual log target under certain circumstances (e.g., an error level message is logged).
If you're using the JDK 1.4 logging facilities, MemoryHandler does exactly this. I'm not sure if the logging system you're using does this, but I imagine you should be able to implement your own appender/handler/whatever that does something similar.
Also, I just want to point out that in your original example, if your concern is variable scope, you could always define a block to reduce the scope of your variable:
{
String myValue = null;
try {
myValue = someObject.getValue();
doSomething(myValue);
}
catch (BadThingsHappenException bthe) {
String pattern = "An error occurred when setting value. [value={}]";
// note that the format method below doesn't barf on nulls
String detail = MessageFormatter.format(pattern, myValue);
// consider this a RuntimeException wrapper class
throw new UnhandledException(detail, bthe);
}
}
Why not keep a local copy/list of all messages that would have gone to the debug log if it was enabled, and pass that to the custom exception when you throw it? Something like:
static void logDebug(String message, List<String> msgs) {
msgs.add(message);
log.debug(message);
}
//...
try {
List<String> debugMsgs = new ArrayList<String>();
String myValue = someObject.getValue();
logDebug("Value: " + myValue, debugMsgs);
doSomething(myValue);
int x = doSomething2();
logDebug("doSomething2() returned " + x, debugMsgs);
}
catch (BadThingsHappenException bthe) {
// at the point when the exception is caught,
// debugMsgs contains some or all of the messages
// which should have gone to the debug log
throw new UnhandledException(bthe, debugMsgs);
}
Your exception class can make use of this List parameter when forming getMessage():
public class UnhandledException extends Exception {
private List<String> debugMessages;
public UnhandledException(String message, List<String> debugMessages) {
super(message);
this.debugMessages = debugMessages;
}
#Override
public String getMessage() {
//return concatentation of super.getMessage() and debugMessages
}
}
The usage of this would be tedious - as you'd have to declare the local variable in every single try/catch where you wanted this type of information - but it might be worth it if you have just a few critical sections of code in which you'd like to maintain this state information on an exception.
You answered your own question. If you want to pass the state to the exception, you need to store your state somewhere.
You have mentioned adding extra variables to do this, but didn't like all the extra variables.
Someone else mentioned a MemoryHandler as a buffer (holds state) between the logger and the application.
These are all the same idea. Create an object that will hold the state you want you show in your exception. Update that object as your code executes. If an error occurs pass that object into the exception.
Exceptions already do this with StackTraceElements. Each thread keeps a list of the stack trace (method, file, line) which represents its 'state'. When the exception happens, it passes the stack trace to the exception.
What you seem to be wanting, is a copy of all the local variables also.
This would mean making a object to hold all your locals and using that object, instead of the locals directly. Then passing the object to the exception.
I have created a key combination in eclipse for a catch block creation.
logmsg as key and the result will be:
catch(SomeException se){
String msg = ""; //$NON-NLS-1$
Object[] args = new Object[]{};
throw new SomeException(Message.format(msg, args), se);
}
You can put as many informations as you want in the Message like:
msg = "Dump:\n varA({0}), varB({1}), varC({2}), varD({3})";
args = new Object[]{varA, varB, varC, varD};
Or some user information:
msg = "Please correct the SMTP client because ({0}) seems to be wrong";
args = new Object[]{ smptClient };
You should think about using log4j as a logger, so you can print your states where ever you want. With the options DEBUG, INFO, ERROR you can define how many loggings you want to see in your log file.
When you deliver your application you will set the log level to ERROR, but when you want to debug your application you can use DEBUG as default.
When you are using a logger, you only have to print a hand full of information in your exception, because the state of some variables you would print into the log file before you are calling the critical try...catch block.
String msg = "Dump:\n varA({0}), varB({1}), varC({2}), varD({3})";
Object[] args = new Object[]{varA, varB, varC, varD};
logger.debug(Message.format(msg, args));
try{
// do action
}catch(ActionException ae){
msg = "Please correct the SMTP client because ({0}) seems to be wrong";
args = new Object[]{ smptClient };
logger.error(Message.format(msg, args), se);
throw new SomeException(Message.format(msg, args), se);
}
If you want to somehow process the details of the error message, you could:
Use an XML text as the message, so you get a structured way:
throw new UnhandledException(String.format(
"<e><m>Unexpected things</m><value>%s</value></e>", value), bthe);
Use your own (and one for every case) exception types to capture variable information into named properties:
throw new UnhandledValueException("Unexpected value things", value, bthe);
Or else you could include it in the raw message, as suggested by others.
As for the type of debug information you need, why don't you just always log the value and don't bother so much with a local try/catch. Just use the Log4J config file to point your debug messages to a different log, or use chainsaw so you can remotely follow the log messages. If all that fails maybe you need a new log message type to add to debug()/info()/warn()/error()/fatal() so you have more control over which messages get sent where. This would be the case when defining appenders in the log4j config file is impractical due to the high number of places where this type of debug logging needs to be inserted.
While we're on the subject, you've touched on one of my pet peeves. Constructing a new exception in the catch block is a code smell.
Catch(MyDBException eDB)
{
throw new UnhandledException("Something bad happened!", eDB);
}
Put the message in the log and then rethrow the exception. Constructing Exceptions is expensive and can easily hide useful debugging information.
First off, inexperienced coders and those who like to cut-n-paste (or begin-mark-bug, end-mark-bug, copy-bug, copy-bug, copy-bug) it can transform easily to this:
Catch(MyDBException eDB)
{
throw new UnhandledException("Something bad happened!");
}
Now you've lost the original stacktrace. Even in the first case, unless the wrapping Exception handles the wrapped exception properly, you can still lose details of the original exception, the stacktrace being the most likely.
Rethrowing exceptions might be necessary but I've found that it should be handled more generally and as a strategy to communicate between layers, like between your business code and the persistance layer, like so:
Catch(SqlException eDB)
{
throw new UnhandledAppException("Something bad happened!", eDB);
}
and in this case, the catch block for the UnhandledAppException is much further up the call stack where we can give the user an indication that they either need to retry their action, report a bug, or whatever.
This let our main() code do something like this
catch(UnhandledAppException uae)
{
\\notify user
\\log exception
}
catch(Throwable tExcp)
{
\\for all other unknown failures
\\log exception
}
finally
{
\\die gracefully
}
Doing it this way meant that local code could catch the immediate and recoverable exceptions where debug logs could be done and the exception not have to be rethrown. This would be like for DivideByZero or maybe a ParseException of some sort.
As for "throws" clauses, having a layer-based exception strategy meant being able to limit the number of exception types that have to be listed for each method.

Categories