I am using System.out.println in my code to track the execution of a program and get some useful output. This creates results like this in the console:
Main function. Program starts.
Method getArea. Getting values
Method getSide. Side is 6
Method getArea. First value is 6
Method getSide. Side is 8
Method getArea. Second value is 8
Method getArea. Area is 48
Main function. The final area is 48
I would like to create tha method, which adds a space in front of the output every time the code goes deeper in the method call stack. For example, the same code but instead of using System.out.println, now with Misc.smartPrintln:
Main function. Program starts.
Method getArea. Getting values
Method getSide. Side is 6
Method getArea. First value is 6
Method getSide. Side is 8
Method getArea. Second value is 8
Method getArea. Area is 48
Main function. The final area is 48
The method would have this definition:
public static void smartPrintln(String string);
I don't know how to implement this functionality. Any ideas how to solve this? And, could the use of a logger offer this functionality?
Create a temporary Throwable object.
Use its getStackTrace() method to analyze the stack and determine the level.
e.g.
public static void smartPrintln(String string) {
Throwable t = new Throwable();
StackTraceElement[] stackElements = t.getStackTrace();
int level = stackElements.length - 1; // don't forget our function adds a level
for (int i = 0; i < level; i++) {
System.out.print(' '); // could probably make this more efficient
}
System.out.println(string);
}
Interesting question. A more condense implementation of #ob1's suggestion:
public static void smartPrintln(String string) {
int i = new Throwable().getStackTrace().length - 1;
System.out.printf("%"+i+"s%s%n", "", string);
}
Another solution would be to "add the functionality" directly to System.out.println calls like this:
System.setOut(new PrintStream(System.out) {
public void println(String x) {
printf("%"+(new Throwable().getStackTrace().length - 1)+"s", "");
super.println(x);
}
});
After this point, all calls to System.out.println(String) will be processed by our "filtering" PrintStream implementation.
Use the Logger API or anyother third party API.
Related
Here is code:
package stacktrace.test;
public class A {
public static void main(String[] args) {
B.f();
}
}
interface B {
static void f() {
C.f();
}
}
interface C {
static void f() {
StackTraceElement[] stackTrace1 = (new Exception()).getStackTrace();
StackTraceElement[] stackTrace2 = Thread.currentThread().getStackTrace();
StackTraceElement x1 = stackTrace1[1];
StackTraceElement x2 = stackTrace2[1];
System.out.println(x1.getClassName());
System.out.println(x2.getClassName());
}
}
And output:
stacktrace.test.B
stacktrace.test.C
I'check the Thread.currentThread().getStackTrace() it calls (new Exception()).getStackTrace();. In such case why I am getting different result?
Thanks in advance!
As you've correctly noticed yourself, Thread.currentThread().getStackTrace() calls (new Exception()).getStackTrace(); This means that the stacktrace of the former will be exactly one frame longer.
If one method calls another, their stack traces cannot be the same by definition.
To understand what is going on, start by printing the entire stack trace item-by-item. Here is what you are going to get (demo):
-- stackTrace1
C.f(Main.java:23)
B.f(Main.java:17)
A.main(Main.java:11)
-- stackTrace2
java.lang.Thread.getStackTrace(Thread.java:1556)
C.f(Main.java:24)
B.f(Main.java:17)
A.main(Main.java:11)
Note that the only difference is in the initial item of the two stack traces: the second one contains an extra frame at the top.
It appears that the method that fills the stack of a Throwable excludes the frame with the constructor of the Throwable or its subclass, along with other methods called on the way to building it.
This makes sense, because when you see the stack trace of an exception you want to see the throwing method at the top, and disregard the fact that creating the exception required you to call its constructor.
Thread's getStackTrace() method, on the other hand, does not remove itself from the stack. That is what you see at the top of the stack when you print it out.
We have a huge project where many methods have been declared upfront and implementations are in progress. All declared methods have a body which simply throws an exception, say, UnimplException.
Now since the methods have been declared and a valid (compilable) body has been provided, they can be called from within other methods.
Now the question is that is there any way to list all such unimplemented (having just a compilable body throwing a particular exception) methods given a particular method?
To illustrate more(the code is to convey the idea and not strictly compiler friendly):
class A {
methA () {
throw new UnimplException();
}
}
class B {
methB () {
// proper body
// and calls methA
A.methA();
// does something else
// and returns.
}
}
class C {
methC () {
// proper body
// calls methB
B.methB();
}
}
So, if we start from, say, methC, then we want to travel all the way down the method tree to reach to methA because methC calls methB (which is properly implemented and we are not interested) which in turn calls methA which is not properly implemented and that is what we want to find.
We want to search for all such unimplemented methods starting from a method and going few levels deep until we cover all such unimplemented methods.
We thought of JavaAssist but we aren't sure how to go down all the levels because it seems to be giving us all methods called from within a method but not recursively.
Any help is greatly appreciated :)
Have you seen this project: https://github.com/gousiosg/java-callgraph? This appears to do the Java introspection part, listing every method call from every method in a jar file. I'd try using that to do the heavy lifting of parsing your code, then just recurse through the results.
Something like:
Use the callgraph code to build a list of all method calls.
Save that data somewhere.
Recursively parse that structure to find matching methods.
So from your example, step 1 would give something like the following:
A:methA -> UnimplException:<init>
B:methB -> A:methA
C:methC -> B:methB
Then shove those in a Multimap and do a fairly straightforward recursive search:
// this is populated from the output of the callgraph code
com.google.common.collect.Multimap<String, String> methodMap;
void checkAllMethods() {
for (String method : methodMap.keySet()) {
List<String> callStack = new ArrayList<>();
if (doesMethodThrowUnimplException(method, callStack)) {
System.out.println(method);
// can print callStack too if interested
}
}
}
boolean doesMethodThrowUnimplException(String method, List<String> callStack) {
for (String child : methodMap.get(method)) {
// have to check the exact method name from callgraph
if (child.equals("UnimplException:<init>")) {
return true;
}
// recurse into child if not already seen
if (!callStack.contains(child)) {
callStack.add(child);
if (doesMethodThrowUnimplException(child, callStack)) {
return true;
}
callStack.remove(callStack.size() - 1);
}
}
return false;
}
Doesn't strictly satisfy your requirements as this will report any method which throws the UnimplException, not those who only throw the exception, but not sure if that matters.
Standard disclaimer - just typed this in - haven't compiled / run it, so may well be typos, but hopefully the idea helps.
I have a simple array class with some methods such as Add(int n), AddAt(int n, int index), etc.
the addAt method calls another method from super class
public void addAt(int n, int index) {
if (checkIndex(index, size + 1)){
...
}
}
that checks if the inserted index is not out-bounded, if so the super class method prints an error message to console.
how should I test that if the message is printed? I am using JUnit4.12-beta
#Test
public void testPrint() {
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
//redirect the System-output (normaly the console) to a variable
System.setErr(new PrintStream(outContent));
//call your method here
//check if your error message is in the output variable
assertEquals("your output", outContent.toString());
}
You could also use a mocking framework to mock the target object and check whether or not the target method has been called.
See for instance http://eclipsesource.com/blogs/2011/10/13/effective-mockito-part-3/
This might be a bit of an investment if you do not have such a framework in place already...
Can't you make your life simpler by raising exceptions rather than printing messages ?
In which case you can use 'expected' exceptions like here : How do you assert that a certain exception is thrown in JUnit 4 tests?
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;
}
}
How do I change two functions that are Mutual Recursive to each other to make them into a linear recursion? Do I have to have both the methods in a single method?
You should be able to simply "inline" the implementation of the second method, into the first method.
That is,
public static void methA() {
// snippet 1
methB();
// snippet 2
}
public static void methB() {
// snippet 3
methA();
// snippet 4
}
becomes
public static void methAB() {
// snippet 1
// snippet 3
methAB();
// snippet 2
// snippet 4
}
If the second method is long, and called from multiple points in the first method, it may get messy though.