How to get method signature (not method name) from Thread.currentThread().getStackTrace()? - java

Suppose I have the following methods and their invocations:
public static void main(String[] args) {zoo();}
public static void zoo() {zoo(0);}
public static void zoo(int i) {too(i);}
public static void too(int i) {...}
Thread.currentThread().getStackTrace() will return me with something like:
A.too(A.java:56)
A.zoo(A.java:65)
A.zoo(A.java:60)
A.main(A.java:80)
With this output, I cannot distinguish the 2 zoos I defined in my example, one without any parameter (zoo()) and one with an integer parameter (zoo(int i)). The reason is because only method names rather than their signatures are outputted. Is there a way to get a stack of method signatures?

The documentation of the StackTraceElement in Java 13 clearly shows that there is no way to do that. You can identify the overloaded method by its line number with your human brain. Automatizing this task would be overkill if even possible (would require using hard reflection), although I do not close out that some lib can do that.
Remark: the binary file format of the .class files actually has the method signature information (at least the parameter list), thus it is not impossible, only no one developed it until now.

You can not get the method signature from a StackTraceElement, but since you’re interested in getting the stack trace of the currentThread, you can use StackWalker instead. Since Java 10, it supports getting the method type from a StackFrame.
For example
public class StackWalkerExample {
public static void main(String[] args) {
zoo();
System.out.println();
Arrays.asList("foo", "bar").sort((a, b) -> { getMethods(); return 0; });
}
public static void zoo() {zoo(0);}
public static void zoo(int i) {too(i);}
public static void too(int i) { getMethods(); }
static void getMethods() {
var sw = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
var methods = sw.walk(frames ->
frames.skip(1).map(StackWalkerExample::toMethod).toArray(Method[]::new));
for(var m: methods) System.out.println(m);
}
static Method toMethod(StackWalker.StackFrame f) {
try {
return f.getDeclaringClass().getDeclaredMethod(
f.getMethodName(), f.getMethodType().parameterArray());
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
}
will print
public static void StackWalkerExample.too(int)
public static void StackWalkerExample.zoo(int)
public static void StackWalkerExample.zoo()
public static void StackWalkerExample.main(java.lang.String[])
private static int StackWalkerExample.lambda$0(java.lang.String,java.lang.String)
private static int java.util.TimSort.countRunAndMakeAscending(java.lang.Object[],int,int,java.util.Comparator)
static void java.util.TimSort.sort(java.lang.Object[],int,int,java.util.Comparator,java.lang.Object[],int,int)
public static void java.util.Arrays.sort(java.lang.Object[],java.util.Comparator)
public void java.util.Arrays$ArrayList.sort(java.util.Comparator)
public static void StackWalkerExample.main(java.lang.String[])
Details of the sorting implementation may vary

Related

Cannot find symbol of written method java.util.function

I have code like
public class Functionz {
public static boolean test() {
return true;
}
public static void main(String[] args) {
Function[] funcs = new Function[] {test}; // and others
for (Function func : funcs) {
func();
}
}
}
and my error is: cannot find symbol: test in the line with the function array declaration.
Hope this isn't a stupid question, very new to java, not new to object oriented languages like python and C++.
A Function in Java does takes one parameter as input and one as output.
You might declare parameter's type this way : Function<Integer, String> is a function that transforms an Integer into a String
Your method test() does not take any input value and outputs a boolean so it's a Supplier.
import java.util.function.Supplier;
public class Main {
public static boolean test() {
System.out.println("lorem ipsum");
return true;
}
public static void main(String[] args) {
Supplier[] funcs = new Supplier[] {Main::test}; // and others
for (Supplier func : funcs) {
func.get();
}
}
}
Your code would compile if test requires one (and only one parameter) like
import java.util.function.Function;
public class Main {
public static boolean test(String str) {
System.out.println(str);
return true;
}
public static void main(String[] args) {
Function[] funcs = new Function[] {(Object anyObject) -> test(anyObject.toString())}; // and others
for (Function func : funcs) {
func.apply("lorem ipsum");
}
}
}
Here's the list of those types
Please note that Function doesn't type its parameters in construction because you can't create arrays with generic type in Java (you might for specific usecases) => Use a List will help you here

Java code - how to remove only annotated methods with script

I wonder if there is a way (a gradle script or any script or any other way without an IDE) to remove methods annotated with certain annotations. Example:
class x {
public static void main(String[] args) {
int x = getValue();
System.out.println(x);
}
#RemoveEnabled(id = "getValueMethod1", return = "10")
int getValue() {
return 20;
}
}
Now when I run the script or gradle target, it should remove the getValue() method, and the output code should become:
class x {
public static void main(String[] args) {
int x = 10;
System.out.println(x);
}
}
Is there an existing script or way to achieve this? It might be achievable with grep and String parsing etc., but I'm looking for a cleaner solution which is able to get all methods by an annotation id, and remove them with formatting. I tried searching on Google, Stack Overflow etc., but couldn't find a solution.
I wrote a module to process similiar task.
https://github.com/KnIfER/Metaline
#StripMethods(keys={"ToRemove","AlsoRemove"})
public class YourCLZ{
void ToRemove(){} // will be removed
void AlsoRemove(){} // will be removed
#StripMethods(strip=true)
void AnotherTest(){} // will also be removed
}
in your case
#StripMethods(keys="getValue")
class yourx {
public static void main(String[] args) {
int x = getValue();
System.out.println(x);
}
int getValue() {
return 20;
}
}
will become:
class yourx {
public static void main(String[] args) {
System.out.println(x);
}
}
you will get a compilation error since for now my module simply remove any methods or method body statements that contain the key you specified.

How do I call a method that has a variable passed through it?

I'm trying to call a method from within another method. I'm understanding this simply enough, until one of those methods needs a variable carried through, and then nothing I try works.
I know that I could do this in one method, but my coursework needs me to lay it out in such a way. Why doesn't this work?
public class test2 {
public static void testMethod() {
int randomNumber = 1;
}
public static void anotherTestMethod(int randomNumber) {
System.out.println(randomNumber);
}
public static void main(String[] args) {
anotherTestMethod();
}
}
You are calling a method that has an int parameter in its signature. You should pass that parameter when calling the method. I think you are trying to use a global variable, in that case, you should declare it outside any method, as a part of the class.
public class test2 {
public static int testMethod() {
int randomNumber = 1;
return randomNumber;
}
public static void anotherTestMethod() {
System.out.println(testMethod());
}
public static void main(String[] args) {
anotherTestMethod();
}
}

Variable Accessible by All Methods Without Parameters?

Is it possible to have a "global" variable, i.e., "balance", which all methods can access without parameters?
Something like:
public static void main(String[] args{
makevariablehere
}
Could be called in another method:
public static int someMethod() {
variable = newVariable;
}
You can define it as a static field on the class. See the example below, which stores the number of args passed to the main method in a static field, so that it may be returned by the getNumberOfArgs() method.
public class MyClass {
private static int argCount;
public static void main(String[] args) {
argCount = args.length;
}
public static int getNumberOfArgs() {
return argCount;
}
}

Program to find the number of methods in a java program

I used the following code to identify the number of functions in a class. Similar way can any one help me to identify the number of functions in a java program. In my program i gave input file as a class. Guide me with the code to give input as a java program and to find the number of declared functions in it.
import java.lang.reflect.*;
import java.io.*;
import java.lang.String.*;
public class Method1 {
private int f1(
Object p, int x) throws NullPointerException
{
if (p == null)
throw new NullPointerException();
return x;
}
public static void main(String args[])throws Exception
{
int Mcount=0,MthdLen=0;
try {
Class cls = Class.forName("Madhu");
int a;
Method methlist[]= cls.getDeclaredMethods();
for (int i = 0; i < methlist.length;i++)
{
Method m = methlist[i];
Mcount = Mcount + 1;
MthdLen=MthdLen+(m.getName().length());
}
}
catch (Throwable e) {
System.err.println(e);
}
System.out.println("Length = " + MthdLen);
System.out.println("Mcount = " + Mcount);
}
}
First of all,
Class cls = Class.forName("Madhu");
Requires the fully qualified name of the desired class. e.g Class.forName("java.lang.Thread")'.
Secondly,
Method methlist[]= cls.getDeclaredMethods();
returns public, protected, private and default method of that specific class only (it excludes inherited methods).
Thirdly,
MthdLen=MthdLen+(m.getName().length());
Sums up the string length of the method name. What do you need this for? You could simply do a count as follows:
int MCount = cls.getDeclaredMethods().length; //If the "getDeclaredMethods()` doesn't return a null.
Finally, if you need to get all inherited public & protected methods of that class, you would do
Class<?> class2 = cls.getSuperClass();
//Get all methods using
Method[] methods2 = class2.getDeclaredMethods();
//Iterate through methods2 and retrieve all public, protected methods and add it to MCount.
Hope this helps.
Java doesn't have any functions so the answer is 0. ;)
If you are looking for the number of methods, you have to ask yourself, do you want to
include inherited methods.
count overriden methods once ore multiple times.
include all the methods in Object or not.
e.g.
public class Main {
static class A {
public String toString() {
return super.toString();
}
}
static class B extends A {
public String toString() {
return super.toString();
}
}
public static void main(String args[]) {
for(Class clazz = B.class;clazz != null;clazz = clazz.getSuperclass()) {
for(Method m: clazz.getDeclaredMethods())
System.out.println(m);
}
}
}
prints
public java.lang.String Main$B.toString()
public java.lang.String Main$A.toString()
protected void java.lang.Object.finalize() throws java.lang.Throwable
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException
private static native void java.lang.Object.registerNatives()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
In JDK6+, you could compile the file at runtime using JavaCompiler, and use your old code to find the number of methods.
EDIT:
Bonus: Replace your code with
System.out.println("Total number of methods: " +
java.beans.Introspector.getBeanInfo( //your class name here
).getMethodDescriptors().length);
i use this code to find out count of method in a class inside of another class.
public class test1 {
public static void main(String[] args)
//if use in class
//Method[] s = getClass.getDeclaredMethods();
Method[] s = SmokeTestTests.class.getDeclaredMethods();
int methodCounter = 0;
for (Method method :
s) {
++methodCounter;
}
System.out.println(methodCounter);
}

Categories

Resources