Related
While refactoring Rultor to use Cactoos instead of Guava, I’m having an issue with negative tests of GithubProfileTest and GithubProfileValidationTest.
After the refactor, the positive test cases pass for both mentioned test classes, but the negative test cases that expect a particular exception fail.
The affected refactored code under test is GithubProfile.assets method and GithubProfile.asset method.
I refactored assets method to look like this:
public Map<String, InputStream> assets() throws IOException {
final XML xml = this.read();
final List<XML> nodes = xml.nodes("/p/entry[#key='assets']/entry");
return new MapOf<>(
new Mapped<>(
nodes,
input ->
new MapEntry<>(
input.xpath("#key").get(0),
this.asset(input.xpath("text()").get(0))
)
)
);
}
On different test cases the this.asset call is expected to throw Profile.ConfigException. Instead, upon calling the assets method, the test fails with a Unable to evaluate the expression Method threw 'java.io.UncheckedIOException' exception, and the Profile.ConfigException is simply ignored/hidden.
It seems that MapOf somehow fails to evaluate, or "hides", the exception that the call to this.asset method raised, raising itself an UncheckedIOException, so I'm unable to fix this and have the Profile.ConfigException raised.
When debugging, the UncheckedIOException doesn't contain any info whatsoever of a Profile.ConfigException being raised.
Any hints on why I might be getting this behaviour or possible solutions?
The problem is that Iterable#next() (in JDK) doesn't allow to throw checked exceptions (like Profile.ConfigException). That's why org.cactoos.iterator.Mapped catches them all and throws UncheckedIOException instead. It's unfixable, thanks to JDK design. The best you can do is good old for loop:
public Map<String, InputStream> assets() throws IOException {
final XML xml = this.read();
final List<XML> nodes = xml.nodes("/p/entry[#key='assets']/entry");
final List<MapEntry> entries = new LinkedList<>();
for (final XML node : nodes) {
entries.add(
new MapEntry<>(
input.xpath("#key").get(0),
this.asset(input.xpath("text()").get(0)) // checked exeption here
)
);
}
return new MapOf<>(entries);
}
The reason is probably the conversion done in org.cactoos.func.UncheckedFunc while iterating to populate the map.
Since functional style programming usually does not play very well with exceptions, the API tries to avoid declaring checked exceptions. So you probably have to live with that.
class CSVReader {
private List<String> output;
private InputStream input;
public CSVReader(InputStream input) {
this.input = input;
}
public void read() throws Exception{
//do something with the inputstream
// create output list.
}
public List<String> getOutput() {
return Collections.unmodifiableList(output);
}
I am trying to create a simple class which will be part of a library. I would like to create code that satisfies the following conditions:
handles all potential errors or wraps them into library errors and
throws them.
creates meaningful and complete object states (no incomplete object structures).
easy to utilize by developers using the library
Now, when I evaluated the code above, against the goals, I realized that I failed badly. A developer using this code would have to write something like this -
CSVReader reader = new CVSReader(new FileInputStream("test.csv");
reader.read();
read.getOutput();
I see the following issues straight away -
- developer has to call read first before getOutput. There is no way for him to know this intuitively and this is probably bad design.
So, I decided to fix the code and write something like this
public List<String> getOutput() throws IOException{
if(output==null)
read();
return Collections.unmodifiableList(output);
}
OR this
public List<String> getOutput() {
if(output==null)
throw new IncompleteStateException("invoke read before getoutput()");
return Collections.unmodifiableList(output);
}
OR this
public CSVReader(InputStream input) {
read(); //throw runtime exception
}
OR this
public List<String> read() throws IOException {
//read and create output list.
// return list
}
What is a good way to achieve my goals? Should the object state be always well defined? - there is never a state where "output" is not defined, so I should create the output as part of constructor? Or should the class ensure that a created instance is always valid, by calling "read" whenever it finds that "output" is not defined and just throw a runtime exception? What is a good approach/ best practice here?
I would make read() private and have getOutput() call it as an implementation detail. If the point of exposing read() is to lazy-load the file, you can do that with exposing getOutput only
public List<String> getOutput() {
if (output == null) {
try {
output = read();
} catch (IOException) {
//here you either wrap into your own exception and then declare it in the signature of getOutput, or just not catch it and make getOutput `throws IOException`
}
}
return Collections.unmodifiableList(output);
}
The advantage of this is that the interface of your class is very trivial: you give me an input (via constructor) I give you an output (via getOutput), no magic order of calls while preserving lazy-loading which is nice if the file is big.
Another advantage of removing read from the public API is that you can go from lazy-loading to eager-loading and viceversa without affecting your clients. If you expose read you have to account for it being called in all possible states of your object (before it's loaded, while it's already running, after it already loaded). In short, always expose the least possible
So to address your specific questions:
Yes, the object state should always be well-defined. Your point of not knowing that an external call on read by the client class is needed is indeed a design smell
Yes, you could call read in the constructor and eagerly load everything upfront. Deciding to lazy-load or not is an implementation detail dependent on your context, it should not matter to a client of your class
Throwing an exception if read has not been called puts again the burden to calling things in the right, implicit order on the client, which is unnecessary due to your comment that output is never really undefined so the implementation itself can make the risk-free decision of when to call read
I would suggest you make your class as small as possible, dropping the getOutput() method all together.
The idea is to have a class that reads a CSV file and returns a list, representing the result. To achieve this, you can expose a single read() method, that will return a List<String>.
Something like:
public class CSVReader {
private final InputStream input;
public CSVReader(String filename) {
this.input = new FileInputStream(filename);
}
public List<String> read() {
// perform the actual reading here
}
}
You have a well defined class, a small interface to maintain and the instances of CSVReader are immutable.
Have getOutput check if it is null (or out of date) and load it in automatically if it is. This allows for a user of your class to not have to care about internal state of the class's file management.
However, you may also want to expose a read function so that the user can chose to load in the file when it is convenient. If you make the class for a concurrent environment, I would recommend doing so.
The first approach takes away some flexibility from the API: before the change the user could call read() in a context where an exception is expected, and then call getOutput() exception-free as many times as he pleases. Your change forces the user to catch a checked exception in contexts where it wasn't necessary before.
The second approach is how it should have been done in the first place: since calling read() is a prerequisite of calling getOutput(), it is a responsibility of your class to "catch" your users when they "forget" to make a call to read().
The third approach hides IOException, which may be a legitimate exception to catch. There is no way to let the user know if the exception is going to be thrown or not, which is a bad practice when designing runtime exceptions.
The root cause of your problem is that the class has two orthogonal responsibilities:
Reading a CSV, and
Storing the result of a read for later use.
If you separate these two responsibilities from each other, you would end up with a cleaner design, in which the users would have no confusion over what they must call, and in what order:
interface CSVData {
List<String> getOutput();
}
class CSVReader {
public static CSVData read(InputStream input) throws IOException {
...
}
}
You could combine the two into a single class with a factory method:
class CSVData {
private CSVData() { // No user instantiation
}
// Getting data is exception-free
public List<String> getOutput() {
...
}
// Creating instances requires a factory call
public static CSVData read(InputStream input) throws IOException {
...
}
}
The ErrorListener mechanism in Antlr4 is great for logging and making decisions about syntax errors as they occur during a parse, but it can get better for batch error handling after the parse is finished. There are a number of reasons you might want to handle errors after the parse finishes, including:
we need a clean way to programmatically check for errors during a parse and handling them after the fact,
sometimes one syntax error causes several others (when not recovered in line, for instance), so it can be helpful to group or nest these errors by parent context when displaying output to the user and you can't know all the errors until the parse is finished,
you may want to display errors differently to the user depending on how many and how severe they are, for example, a single error that exited a rule or a few errors all recovered in line might just ask the user to fix these local areas - otherwise, you might have the user edit the entire input, and you need to have all the errors to make this determination.
The bottom line is that we can be smarter about reporting and asking users to fix syntax errors if we know the full context in which the errors occurred (including other errors). To do this, I have the following three goals:
a full collection of all the errors from a given parse,
context information for each error, and
severity and recovery information for each error.
I have written code to do #1 and #2, and I'm looking for help on #3. I'm also going to suggest some small changes to make #1 and #2 easier for everyone.
First, to accomplish #1 (a full collection of errors), I created CollectionErrorListener as follows:
public class CollectionErrorListener extends BaseErrorListener {
private final List<SyntaxError> errors = new ArrayList<SyntaxError>();
public List<SyntaxError> getErrors() {
return errors;
}
#Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
if (e == null) {
// e is null when the parser was able to recover in line without exiting the surrounding rule.
e = new InlineRecognitionException(msg, recognizer, ((Parser)recognizer).getInputStream(), ((Parser)recognizer).getContext(), (Token) offendingSymbol);
}
this.errors.add(new SyntaxError(msg, e));
}
}
And here is my class for InlineRecognitionException:
public class InlineRecognitionException extends RecognitionException {
public InlineRecognitionException(String message, Recognizer<?, ?> recognizer, IntStream input, ParserRuleContext ctx, Token offendingToken) {
super(message, recognizer, input, ctx);
this.setOffendingToken(offendingToken);
}
}
And here is my class for the SyntaxError container:
public class SyntaxError extends RecognitionException {
public SyntaxError(String message, RecognitionException e) {
super(message, e.getRecognizer(), e.getInputStream(), (ParserRuleContext) e.getCtx());
this.setOffendingToken(e.getOffendingToken());
this.initCause(e);
}
}
This is very similar to the SyntaxErrorListener referred to by 280Z28's answer to Antlr error/exception handling. I need both the InlineRecognitionException and the SyntaxError wrapper because of how the parameters of CollectionErrorListener.syntaxError are filled.
First of all, the RecognitionException parameter "e" is null if the parser recovered from the exception in line (without leaving the rule). We can't just instantiate a new RecognitionException because there is no constructor or method that allows us to set the offending token. Anyway, being able to differentiate errors that were recovered in line (using an instanceof test) is useful information for achieving goal #3, so we can use the class of InlineRecognitionException to indicate in line recovery.
Next, we need the SyntaxError wrapper class because, even when RecognitionException "e" is not null (e.g., when recovery was not in line), the value of e.getMessage() is null (for some unknown reason). We therefore need to store the msg parameter to CollectionErrorListener.syntaxError. Because there is no setMessage() modifier method on RecognitionException, and we can't just instantiate a new RecognitionException (we lose the offending token information as discussed in the previous paragraph), we are left subclassing to be able to set the message, offending token, and cause appropriately.
And this mechanism works really well:
CollectionErrorListener collector = new CollectionErrorListener();
parser.addErrorListener(collector);
ParseTree tree = parser.prog();
// ... Later ...
for (SyntaxError e : collector.getErrors()) {
// RecognitionExceptionUtil is my custom class discussed next.
System.out.println(RecognitionExceptionUtil.formatVerbose(e));
}
This gets to my next point. Formatting output from a RecognitionException is kinda annoying. Chapter 9 of The Definitive ANTLR 4 Reference book shows how displaying quality error messages means you need to split the input lines, reverse the rule invocation stack, and piece together a lot of stuff from the offending token to explain where the error occurred. And, the following command doesn't work if you are reporting errors after the parse is finished:
// The following doesn't work if you are not reporting during the parse because the
// parser context is lost from the RecognitionException "e" recognizer.
List<String> stack = ((Parser)e.getRecognizer()).getRuleInvocationStack();
The problem is that we have lost the RuleContext, and that is needed for getRuleInvocationStack. Luckily, RecognitionException keeps a copy of our context and getRuleInvocationStack takes a parameter, so here is how we get the rule invocation stack after the parse is finished:
// Pass in the context from RecognitionException "e" to get the rule invocation stack
// after the parse is finished.
List<String> stack = ((Parser)e.getRecognizer()).getRuleInvocationStack(e.getCtx());
In general, it would be especially nice if we had some convenience methods in RecognitionException to make error reporting more friendly. Here is my first attempt at a utility class of methods that could be part of RecognitionException:
public class RecognitionExceptionUtil {
public static String formatVerbose(RecognitionException e) {
return String.format("ERROR on line %s:%s => %s%nrule stack: %s%noffending token %s => %s%n%s",
getLineNumberString(e),
getCharPositionInLineString(e),
e.getMessage(),
getRuleStackString(e),
getOffendingTokenString(e),
getOffendingTokenVerboseString(e),
getErrorLineStringUnderlined(e).replaceAll("(?m)^|$", "|"));
}
public static String getRuleStackString(RecognitionException e) {
if (e == null || e.getRecognizer() == null
|| e.getCtx() == null
|| e.getRecognizer().getRuleNames() == null) {
return "";
}
List<String> stack = ((Parser)e.getRecognizer()).getRuleInvocationStack(e.getCtx());
Collections.reverse(stack);
return stack.toString();
}
public static String getLineNumberString(RecognitionException e) {
if (e == null || e.getOffendingToken() == null) {
return "";
}
return String.format("%d", e.getOffendingToken().getLine());
}
public static String getCharPositionInLineString(RecognitionException e) {
if (e == null || e.getOffendingToken() == null) {
return "";
}
return String.format("%d", e.getOffendingToken().getCharPositionInLine());
}
public static String getOffendingTokenString(RecognitionException e) {
if (e == null || e.getOffendingToken() == null) {
return "";
}
return e.getOffendingToken().toString();
}
public static String getOffendingTokenVerboseString(RecognitionException e) {
if (e == null || e.getOffendingToken() == null) {
return "";
}
return String.format("at tokenStream[%d], inputString[%d..%d] = '%s', tokenType<%d> = %s, on line %d, character %d",
e.getOffendingToken().getTokenIndex(),
e.getOffendingToken().getStartIndex(),
e.getOffendingToken().getStopIndex(),
e.getOffendingToken().getText(),
e.getOffendingToken().getType(),
e.getRecognizer().getTokenNames()[e.getOffendingToken().getType()],
e.getOffendingToken().getLine(),
e.getOffendingToken().getCharPositionInLine());
}
public static String getErrorLineString(RecognitionException e) {
if (e == null || e.getRecognizer() == null
|| e.getRecognizer().getInputStream() == null
|| e.getOffendingToken() == null) {
return "";
}
CommonTokenStream tokens =
(CommonTokenStream)e.getRecognizer().getInputStream();
String input = tokens.getTokenSource().getInputStream().toString();
String[] lines = input.split(String.format("\r?\n"));
return lines[e.getOffendingToken().getLine() - 1];
}
public static String getErrorLineStringUnderlined(RecognitionException e) {
String errorLine = getErrorLineString(e);
if (errorLine.isEmpty()) {
return errorLine;
}
// replace tabs with single space so that charPositionInLine gives us the
// column to start underlining.
errorLine = errorLine.replaceAll("\t", " ");
StringBuilder underLine = new StringBuilder(String.format("%" + errorLine.length() + "s", ""));
int start = e.getOffendingToken().getStartIndex();
int stop = e.getOffendingToken().getStopIndex();
if ( start>=0 && stop>=0 ) {
for (int i=0; i<=(stop-start); i++) {
underLine.setCharAt(e.getOffendingToken().getCharPositionInLine() + i, '^');
}
}
return String.format("%s%n%s", errorLine, underLine);
}
}
There is a lot to be desired in my RecognitionExceptionUtil (always returning strings, not checking that recognizer is of type Parser, not handling multiple lines in getErrorLineString, etc), but I'm hoping you get the idea.
SUMMARY of my suggestions for a future version of ANTLR:
Always populate the "RecognitionException e" parameter of ANTLRErrorListener.syntaxError (including the OffendingToken) so that we can collect these exceptions for batch handling after the parse. While your at it, make sure the e.getMessage() is set to return the value currently in the msg parameter.
Add a constructor for RecognitionException that includes OffendingToken.
Remove the other parameters in the method signature of ANTLRErrorListener.syntaxError since they will be extraneous and lead to confusion.
Add convenience methods in RecognitionException for common stuff such as getCharPositionInLine, getLineNumber, getRuleStack, and the rest of my stuff from my RecognitionExceptionUtil class defined above. Of course, these will have to check for null and also check that recognizer is of type Parser for some of these methods.
When calling ANTLRErrorListener.syntaxError, clone the recognizer so that we don't lose the context when the parse finishes (and we can more easily call getRuleInvocationStack).
If you clone the recognizer, you won't need to store the context in RecognitionException. We can make two changes to e.getCtx(): first, rename it to e.getContext() to make it consistent with Parser.getContext(), and second, make it a convenience method for the recognizer we already have in RecognitionException (checking that recognizer is an instance of Parser).
Include information in RecognitionException about the severity of the error and how the parser recovered. This is my goal #3 from the beginning. It would be great to categorize syntax errors by how well the parser handled it. Did this error blow up the entire parse or just show up as a blip in line? How many and which tokens were skipped / inserted?
So, I'm looking for feedback on my three goals and especially any suggestions for gathering more information about goal #3: severity and recovery information for each error.
I posted these suggestions to the Antlr4 GitHub Issue list and received the below reply. I believe that the ANTLRErrorListener.syntaxError method contains redundant / confusing parameters and requires a lot of API knowledge to use properly, but I understand the decision. Here is the link to the issue and a copy of the text response:
From: https://github.com/antlr/antlr4/issues/396
Regarding your suggestions:
Populating the RecognitionException e argument to syntaxError: As mentioned in the documentation:
The RecognitionException is non-null for all syntax errors except when
we discover mismatched token errors that we can recover from in-line,
without returning from the surrounding rule (via the single token
insertion and deletion mechanism).
Adding a constructor to RecognitionException with the offending token: This is not really relevant to this issue, and would be addressed separately (if at all).
Removing parameters from syntaxError: This would not only introduce breaking changes for users who have implemented this method in previous releases of ANTLR 4, but it would eliminate the ability to report the available information for errors which occurred inline (i.e. errors where no RecognitionException is available).
Convenience methods in RecognitionException: This is not really relevant to this issue, and would be addressed separately (if at all). (Further note: It's hard enough as-is to document the API. This just adds more ways to do things that are already readily accessible, so I oppose this change.)
Cloning the recognizer when calling syntaxError: This is a performance-critical method, so new objects are only created when absolutely necessary.
"If cloning the recognizer": The recognizer will never be cloned before calling syntaxError.
This information can be stored in an associative map in your implementation of ANTLRErrorListener and/or ANTLRErrorStrategy if necessary for your application.
I'm closing this issue for now since I don't see any action items requiring changes to the runtime from this list.
This question already has answers here:
How to get the name of the calling class in Java?
(13 answers)
Closed 6 years ago.
I want to get the caller class of the method, i.e.
class foo{
bar();
}
In the method bar, I need to get the class name foo, and I found this method:
Class clazz = sun.reflect.Reflection.getCallerClass(1);
However, even though getCallerClass is public, when I try to call it Eclipse says:
Access restriction: The method getCallerClass() from the type
Reflection is not accessible due to restriction on required library
C:\Program Files\Java\jre7\lib\rt.jar
Are there any other choices?
You can generate a stack trace and use the informations in the StackTraceElements.
For example an utility class can return you the calling class name :
public class KDebug {
public static String getCallerClassName() {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
for (int i=1; i<stElements.length; i++) {
StackTraceElement ste = stElements[i];
if (!ste.getClassName().equals(KDebug.class.getName()) && ste.getClassName().indexOf("java.lang.Thread")!=0) {
return ste.getClassName();
}
}
return null;
}
}
If you call KDebug.getCallerClassName() from bar(), you'll get "foo".
Now supposing you want to know the class of the method calling bar (which is more interesting and maybe what you really wanted). You could use this method :
public static String getCallerCallerClassName() {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
String callerClassName = null;
for (int i=1; i<stElements.length; i++) {
StackTraceElement ste = stElements[i];
if (!ste.getClassName().equals(KDebug.class.getName())&& ste.getClassName().indexOf("java.lang.Thread")!=0) {
if (callerClassName==null) {
callerClassName = ste.getClassName();
} else if (!callerClassName.equals(ste.getClassName())) {
return ste.getClassName();
}
}
}
return null;
}
Is that for debugging ? If not, there may be a better solution to your problem.
StackTrace
This Highly depends on what you are looking for... But this should get the class and method that called this method within this object directly.
index 0 = Thread
index 1 = this
index 2 = direct caller, can be self.
index 3 ... n = classes and methods that called each other to get to the index 2 and below.
For Class/Method/File name:
Thread.currentThread().getStackTrace()[2].getClassName();
Thread.currentThread().getStackTrace()[2].getMethodName();
Thread.currentThread().getStackTrace()[2].getFileName();
For Class:
Class.forName(Thread.currentThread().getStackTrace()[2].getClassName())
FYI: Class.forName() throws a ClassNotFoundException which is NOT runtime. Youll need try catch.
Also, if you are looking to ignore the calls within the class itself, you have to add some looping with logic to check for that particular thing.
Something like... (I have not tested this piece of code so beware)
StackTraceElement[] stes = Thread.currentThread().getStackTrace();
for(int i=2;i<stes.length;i++)
if(!stes[i].getClassName().equals(this.getClass().getName()))
return stes[i].getClassName();
StackWalker
StackWalker StackFrame
Note that this is not an extensive guide but an example of the possibility.
Prints the Class of each StackFrame (by grabbing the Class reference)
StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.forEach(frame -> System.out.println(frame.getDeclaringClass()));
Does the same thing but first collects the stream into a List.
Just for demonstration purposes.
StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.walk(stream -> stream.collect(Collectors.toList()))
.forEach(frame -> System.out.println(frame.getDeclaringClass()));
To get caller/called class name use below code, it works fine for me.
String callerClassName = new Exception().getStackTrace()[1].getClassName();
String calleeClassName = new Exception().getStackTrace()[0].getClassName();
SecurityManager has a protected method getClassContext
By creating a utility class which extends SecurityManager, you can access this.
public class CallingClass extends SecurityManager {
public static final CallingClass INSTANCE = new CallingClass();
public Class[] getCallingClasses() {
return getClassContext();
}
}
Use CallingClass.INSTANCE.getCallingClasses() to retrieve the calling classes.
There is also a small library (disclaimer: mine) WhoCalled which exposes this information. It uses Reflection.getCallerClass when available, else falls back to SecurityManager.
I know this is an old question but I believed the asker wanted the class, not the class name. I wrote a little method that will get the actual class. It is sort of cheaty and may not always work, but sometimes when you need the actual class, you will have to use this method...
/**
* Get the caller class.
* #param level The level of the caller class.
* For example: If you are calling this class inside a method and you want to get the caller class of that method,
* you would use level 2. If you want the caller of that class, you would use level 3.
*
* Usually level 2 is the one you want.
* #return The caller class.
* #throws ClassNotFoundException We failed to find the caller class.
*/
public static Class getCallerClass(int level) throws ClassNotFoundException {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
String rawFQN = stElements[level+1].toString().split("\\(")[0];
return Class.forName(rawFQN.substring(0, rawFQN.lastIndexOf('.')));
}
This is the most efficient way to get just the callers class. Other approaches take an entire stack dump and only give you the class name.
However, this class in under sun.* which is really for internal use. This means that it may not work on other Java platforms or even other Java versions. You have to decide whether this is a problem or not.
The error message the OP is encountering is just an Eclipse feature. If you are willing to tie your code to a specific maker (and even version) of the JVM, you can effectively use method sun.reflect.Reflection.getCallerClass(). You can then compile the code outside of Eclipse or configure it not to consider this diagnostic an error.
The worse Eclipse configuration is to disable all occurrences of the error by:
Project Properties / Java Compiler / Errors/Warnings / Enable project specific settings set to checked / Deprecated and restrited API / Forbidden reference (access rules) set to Warning or Ignore.
The better Eclipse configuration is to disable a specific occurrence of the error by:
Project Properties / Java Build Path / Libraries / JRE System Library expand / Access rules: select / Edit... / Add... / Resolution: set to Discouraged or Accessible / Rule Pattern set to sun/reflect/Reflection.
Find below a simple example illustrating how to get class and method names.
public static void main(String args[])
{
callMe();
}
void callMe()
{
try
{
throw new Exception("Who called me?");
}
catch( Exception e )
{
System.out.println( "I was called by " +
e.getStackTrace()[1].getClassName() +
"." +
e.getStackTrace()[1].getMethodName() +
"()!" );
}
}
e has getClassName(), getFileName(), getLineNumber() and getMethodName()...
Since I currently have the same problem here is what I do:
I prefer com.sun.Reflection instead of stackTrace since a stack trace is only producing the name not the class (including the classloader) itself.
The method is deprecated but still around in Java 8 SDK.
// Method descriptor #124 (I)Ljava/lang/Class; (deprecated)
// Signature: (I)Ljava/lang/Class<*>;
#java.lang.Deprecated
public static native java.lang.Class getCallerClass(int arg0);
The method without int argument is not deprecated
// Method descriptor #122 ()Ljava/lang/Class;
// Signature: ()Ljava/lang/Class<*>;
#sun.reflect.CallerSensitive
public static native java.lang.Class getCallerClass();
Since I have to be platform independent bla bla including Security Restrictions, I just create a flexible method:
Check if com.sun.Reflection is available (security exceptions disable this mechanism)
If 1 is yes then get the method with int or no int argument.
If 2 is yes call it.
If 3. was never reached, I use the stack trace to return the name. I use a special result object that contains either the class or the string and this object tells exactly what it is and why.
[Summary]
I use stacktrace for backup and to bypass eclipse compiler warnings I use reflections. Works very good. Keeps the code clean, works like a charm and also states the problems involved correctly.
I use this for quite a long time and today I searched a related question so
i am using the following method to get the caller for a specific class from the stacktrace:
package test.log;
public class CallerClassTest {
public static void main(final String[] args) {
final Caller caller = new Caller(new Callee());
caller.execute();
}
private static class Caller {
private final Callee c;
public Caller(final Callee c) {
this.c = c;
}
void execute() {
c.call();
}
}
static class Callee {
void call() {
System.out.println(getCallerClassName(this.getClass()));
}
}
/**
* Searches the current threads stacktrace for the class that called the given class. Returns {#code null} if the
* calling class could not be found.
*
* #param clazz
* the class that has been called
*
* #return the caller that called the class or {#code null}
*/
public static String getCallerClassName(final Class<?> clazz) {
final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
final String className = clazz.getName();
boolean classFound = false;
for (int i = 1; i < stackTrace.length; i++) {
final StackTraceElement element = stackTrace[i];
final String callerClassName = element.getClassName();
// check if class name is the requested class
if (callerClassName.equals(className)) classFound = true;
else if (classFound) return callerClassName;
}
return null;
}
}
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.