Java: Easy way of passing a method as a parameter [duplicate] - java

I need to find the caller of a method. Is it possible using stacktrace or reflection?

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()
According to the Javadocs:
The last element of the array represents the bottom of the stack, which is the least recent method invocation in the sequence.
A StackTraceElement has getClassName(), getFileName(), getLineNumber() and getMethodName().
You will have to experiment to determine which index you want
(probably stackTraceElements[1] or [2]).

Note: if you are using Java 9 or later you should use StackWalker.getCallerClass() as described in Ali Dehghani's answer.
The comparison of different methods below is mostly interesting for historical reason.
An alternative solution can be found in a comment to this request for enhancement.
It uses the getClassContext() method of a custom SecurityManager and seems to be faster than the stack trace method.
The following program tests the speed of the different suggested methods (the most interesting bit is in the inner class SecurityManagerMethod):
/**
* Test the speed of various methods for getting the caller class name
*/
public class TestGetCallerClassName {
/**
* Abstract class for testing different methods of getting the caller class name
*/
private static abstract class GetCallerClassNameMethod {
public abstract String getCallerClassName(int callStackDepth);
public abstract String getMethodName();
}
/**
* Uses the internal Reflection class
*/
private static class ReflectionMethod extends GetCallerClassNameMethod {
public String getCallerClassName(int callStackDepth) {
return sun.reflect.Reflection.getCallerClass(callStackDepth).getName();
}
public String getMethodName() {
return "Reflection";
}
}
/**
* Get a stack trace from the current thread
*/
private static class ThreadStackTraceMethod extends GetCallerClassNameMethod {
public String getCallerClassName(int callStackDepth) {
return Thread.currentThread().getStackTrace()[callStackDepth].getClassName();
}
public String getMethodName() {
return "Current Thread StackTrace";
}
}
/**
* Get a stack trace from a new Throwable
*/
private static class ThrowableStackTraceMethod extends GetCallerClassNameMethod {
public String getCallerClassName(int callStackDepth) {
return new Throwable().getStackTrace()[callStackDepth].getClassName();
}
public String getMethodName() {
return "Throwable StackTrace";
}
}
/**
* Use the SecurityManager.getClassContext()
*/
private static class SecurityManagerMethod extends GetCallerClassNameMethod {
public String getCallerClassName(int callStackDepth) {
return mySecurityManager.getCallerClassName(callStackDepth);
}
public String getMethodName() {
return "SecurityManager";
}
/**
* A custom security manager that exposes the getClassContext() information
*/
static class MySecurityManager extends SecurityManager {
public String getCallerClassName(int callStackDepth) {
return getClassContext()[callStackDepth].getName();
}
}
private final static MySecurityManager mySecurityManager =
new MySecurityManager();
}
/**
* Test all four methods
*/
public static void main(String[] args) {
testMethod(new ReflectionMethod());
testMethod(new ThreadStackTraceMethod());
testMethod(new ThrowableStackTraceMethod());
testMethod(new SecurityManagerMethod());
}
private static void testMethod(GetCallerClassNameMethod method) {
long startTime = System.nanoTime();
String className = null;
for (int i = 0; i < 1000000; i++) {
className = method.getCallerClassName(2);
}
printElapsedTime(method.getMethodName(), startTime);
}
private static void printElapsedTime(String title, long startTime) {
System.out.println(title + ": " + ((double)(System.nanoTime() - startTime))/1000000 + " ms.");
}
}
An example of the output from my 2.4 GHz Intel Core 2 Duo MacBook running Java 1.6.0_17:
Reflection: 10.195 ms.
Current Thread StackTrace: 5886.964 ms.
Throwable StackTrace: 4700.073 ms.
SecurityManager: 1046.804 ms.
The internal Reflection method is much faster than the others. Getting a stack trace from a newly created Throwable is faster than getting it from the current Thread. And among the non-internal ways of finding the caller class the custom SecurityManager seems to be the fastest.
Update
As lyomi points out in this comment the sun.reflect.Reflection.getCallerClass() method has been disabled by default in Java 7 update 40 and removed completely in Java 8. Read more about this in this issue in the Java bug database.
Update 2
As zammbi has found, Oracle was forced to back out of the change that removed the sun.reflect.Reflection.getCallerClass(). It is still available in Java 8 (but it is deprecated).
Update 3
3 years after: Update on timing with current JVM.
> java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
> java TestGetCallerClassName
Reflection: 0.194s.
Current Thread StackTrace: 3.887s.
Throwable StackTrace: 3.173s.
SecurityManager: 0.565s.

Java 9 - JEP 259: Stack-Walking API
JEP 259 provides an efficient standard API for stack walking that allows easy filtering of, and lazy access to, the information in stack traces. Before Stack-Walking API, common ways of accessing stack frames were:
Throwable::getStackTrace and Thread::getStackTrace return an array of
StackTraceElement objects, which contain the class name and method
name of each stack-trace element.
SecurityManager::getClassContext is a protected method, which allows a
SecurityManager subclass to access the class context.
JDK-internal sun.reflect.Reflection::getCallerClass method which you shouldn't use anyway
Using these APIs are usually inefficient:
These APIs require the VM to eagerly capture a snapshot of the entire
stack, and they return information representing the entire stack.
There is no way to avoid the cost of examining all the frames if the
caller is only interested in the top few frames on the stack.
In order to find the immediate caller's class, first obtain a StackWalker:
StackWalker walker = StackWalker
.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
Then either call the getCallerClass():
Class<?> callerClass = walker.getCallerClass();
or walk the StackFrames and get the first preceding StackFrame:
walker.walk(frames -> frames
.map(StackWalker.StackFrame::getDeclaringClass)
.skip(1)
.findFirst());

Sounds like you're trying to avoid passing a reference to this into the method. Passing this is way better than finding the caller through the current stack trace. Refactoring to a more OO design is even better. You shouldn't need to know the caller. Pass a callback object if necessary.

Oneliner:
Thread.currentThread().getStackTrace()[2].getMethodName()
Note that you might need to replace the 2 with 1.

This method does the same thing but a little more simply and possibly a little more performant and in the event you are using reflection, it skips those frames automatically. The only issue is it may not be present in non-Sun JVMs, although it is included in the runtime classes of JRockit 1.4-->1.6. (Point is, it is not a public class).
sun.reflect.Reflection
/** Returns the class of the method <code>realFramesToSkip</code>
frames up the stack (zero-based), ignoring frames associated
with java.lang.reflect.Method.invoke() and its implementation.
The first frame is that associated with this method, so
<code>getCallerClass(0)</code> returns the Class object for
sun.reflect.Reflection. Frames associated with
java.lang.reflect.Method.invoke() and its implementation are
completely ignored and do not count toward the number of "real"
frames skipped. */
public static native Class getCallerClass(int realFramesToSkip);
As far as what the realFramesToSkip value should be, the Sun 1.5 and 1.6 VM versions of java.lang.System, there is a package protected method called getCallerClass() which calls sun.reflect.Reflection.getCallerClass(3), but in my helper utility class I used 4 since there is the added frame of the helper class invocation.

/**
* Get the method name for a depth in call stack. <br />
* Utility function
* #param depth depth in the call stack (0 means current method, 1 means call method, ...)
* #return method name
*/
public static String getMethodName(final int depth)
{
final StackTraceElement[] ste = new Throwable().getStackTrace();
//System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName());
return ste[ste.length - depth].getMethodName();
}
For example, if you try to get the calling method line for debug purpose, you need to get past the Utility class in which you code those static methods:
(old java1.4 code, just to illustrate a potential StackTraceElement usage)
/**
* Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils". <br />
* From the Stack Trace.
* #return "[class#method(line)]: " (never empty, first class past StackTraceUtils)
*/
public static String getClassMethodLine()
{
return getClassMethodLine(null);
}
/**
* Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils" and aclass. <br />
* Allows to get past a certain class.
* #param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils.
* #return "[class#method(line)]: " (never empty, because if aclass is not found, returns first class past StackTraceUtils)
*/
public static String getClassMethodLine(final Class aclass)
{
final StackTraceElement st = getCallingStackTraceElement(aclass);
final String amsg = "[" + st.getClassName() + "#" + st.getMethodName() + "(" + st.getLineNumber()
+")] <" + Thread.currentThread().getName() + ">: ";
return amsg;
}
/**
* Returns the first stack trace element of the first class not equal to "StackTraceUtils" or "LogUtils" and aClass. <br />
* Stored in array of the callstack. <br />
* Allows to get past a certain class.
* #param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils.
* #return stackTraceElement (never null, because if aClass is not found, returns first class past StackTraceUtils)
* #throws AssertionFailedException if resulting statckTrace is null (RuntimeException)
*/
public static StackTraceElement getCallingStackTraceElement(final Class aclass)
{
final Throwable t = new Throwable();
final StackTraceElement[] ste = t.getStackTrace();
int index = 1;
final int limit = ste.length;
StackTraceElement st = ste[index];
String className = st.getClassName();
boolean aclassfound = false;
if(aclass == null)
{
aclassfound = true;
}
StackTraceElement resst = null;
while(index < limit)
{
if(shouldExamine(className, aclass) == true)
{
if(resst == null)
{
resst = st;
}
if(aclassfound == true)
{
final StackTraceElement ast = onClassfound(aclass, className, st);
if(ast != null)
{
resst = ast;
break;
}
}
else
{
if(aclass != null && aclass.getName().equals(className) == true)
{
aclassfound = true;
}
}
}
index = index + 1;
st = ste[index];
className = st.getClassName();
}
if(resst == null)
{
//Assert.isNotNull(resst, "stack trace should null"); //NO OTHERWISE circular dependencies
throw new AssertionFailedException(StackTraceUtils.getClassMethodLine() + " null argument:" + "stack trace should null"); //$NON-NLS-1$
}
return resst;
}
static private boolean shouldExamine(String className, Class aclass)
{
final boolean res = StackTraceUtils.class.getName().equals(className) == false && (className.endsWith("LogUtils"
) == false || (aclass !=null && aclass.getName().endsWith("LogUtils")));
return res;
}
static private StackTraceElement onClassfound(Class aclass, String className, StackTraceElement st)
{
StackTraceElement resst = null;
if(aclass != null && aclass.getName().equals(className) == false)
{
resst = st;
}
if(aclass == null)
{
resst = st;
}
return resst;
}

I've done this before. You can just create a new exception and grab the stack trace on it without throwing it, then examine the stack trace. As the other answer says though, it's extremely costly--don't do it in a tight loop.
I've done it before for a logging utility on an app where performance didn't matter much (Performance rarely matters much at all, actually--as long as you display the result to an action such as a button click quickly).
It was before you could get the stack trace, exceptions just had .printStackTrace() so I had to redirect System.out to a stream of my own creation, then (new Exception()).printStackTrace(); Redirect System.out back and parse the stream. Fun stuff.

private void parseExceptionContents(
final Exception exception,
final OutputStream out)
{
final StackTraceElement[] stackTrace = exception.getStackTrace();
int index = 0;
for (StackTraceElement element : stackTrace)
{
final String exceptionMsg =
"Exception thrown from " + element.getMethodName()
+ " in class " + element.getClassName() + " [on line number "
+ element.getLineNumber() + " of file " + element.getFileName() + "]";
try
{
out.write((headerLine + newLine).getBytes());
out.write((headerTitlePortion + index++ + newLine).getBytes() );
out.write((headerLine + newLine).getBytes());
out.write((exceptionMsg + newLine + newLine).getBytes());
out.write(
("Exception.toString: " + element.toString() + newLine).getBytes());
}
catch (IOException ioEx)
{
System.err.println(
"IOException encountered while trying to write "
+ "StackTraceElement data to provided OutputStream.\n"
+ ioEx.getMessage() );
}
}
}

Here is a part of the code that I made based in the hints showed in this topic.
Hope it helps.
(Feel free to make any suggestions to improve this code, please tell me)
The counter:
public class InstanceCount{
private static Map<Integer, CounterInstanceLog> instanceMap = new HashMap<Integer, CounterInstanceLog>();
private CounterInstanceLog counterInstanceLog;
public void count() {
counterInstanceLog= new counterInstanceLog();
if(counterInstanceLog.getIdHashCode() != 0){
try {
if (instanceMap .containsKey(counterInstanceLog.getIdHashCode())) {
counterInstanceLog= instanceMap .get(counterInstanceLog.getIdHashCode());
}
counterInstanceLog.incrementCounter();
instanceMap .put(counterInstanceLog.getIdHashCode(), counterInstanceLog);
}
(...)
}
And the object:
public class CounterInstanceLog{
private int idHashCode;
private StackTraceElement[] arrayStackTraceElements;
private int instanceCount;
private String callerClassName;
private StackTraceElement getProjectClasses(int depth) {
if(depth< 10){
getCallerClassName(sun.reflect.Reflection.getCallerClass(depth).getName());
if(getCallerClassName().startsWith("com.yourproject.model")){
setStackTraceElements(Thread.currentThread().getStackTrace());
setIdHashCode();
return arrayStackTraceElements[depth];
}
//+2 because one new item are added to the stackflow
return getProjectClasses(profundidade+2);
}else{
return null;
}
}
private void setIdHashCode() {
if(getNomeClasse() != null){
this.idHashCode = (getCallerClassName()).hashCode();
}
}
public void incrementaContador() {
this.instanceCount++;
}
//getters and setters
(...)
}

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
class DBConnection {
String createdBy = null;
DBConnection(Throwable whoCreatedMe) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(os);
whoCreatedMe.printStackTrace(pw);
try {
createdBy = os.toString();
pw.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ThrowableTest {
public static void main(String[] args) {
Throwable createdBy = new Throwable(
"Connection created from DBConnectionManager");
DBConnection conn = new DBConnection(createdBy);
System.out.println(conn.createdBy);
}
}
OR
public static interface ICallback<T> { T doOperation(); }
public class TestCallerOfMethod {
public static <T> T callTwo(final ICallback<T> c){
// Pass the object created at callee to the caller
// From the passed object we can get; what is the callee name like below.
System.out.println(c.getClass().getEnclosingMethod().getName());
return c.doOperation();
}
public static boolean callOne(){
ICallback callBackInstance = new ICallback(Boolean){
#Override
public Boolean doOperation()
{
return true;
}
};
return callTwo(callBackInstance);
}
public static void main(String[] args) {
callOne();
}
}

use this method:-
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
stackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
System.out.println(e.getMethodName());
Caller of method example Code is here:-
public class TestString {
public static void main(String[] args) {
TestString testString = new TestString();
testString.doit1();
testString.doit2();
testString.doit3();
testString.doit4();
}
public void doit() {
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
System.out.println(e.getMethodName());
}
public void doit1() {
doit();
}
public void doit2() {
doit();
}
public void doit3() {
doit();
}
public void doit4() {
doit();
}
}

Short answer ReflectionUtils.getCallingClass(0)
Long answer (code, Groovy)
package my
import org.codehaus.groovy.reflection.ReflectionUtils
import java.lang.reflect.Field
import java.lang.reflect.Method
trait Reflector {
static String[] fieldNames() {
List<String> names = []
Arrays.asList(naturalFields()).forEach { Field fl -> names.add(fl.name) }
return names.toArray() as String[]
}
static Field[] naturalFields() {
return finalClass().getDeclaredFields().findAll { Field fl -> !fl.synthetic }.collect()
}
static Method[] naturalMethods() {
return finalClass().getDeclaredMethods().findAll { Method md -> !md.synthetic }.collect()
}
static Class finalClass() {
return ReflectionUtils.getCallingClass(0)
}
}
class Demo implements Reflector {
int archived = 0
int demo = 100
static void playToo() {
println finalClass()
}
}
println Demo.finalClass() // class my.Demo
println Demo.naturalFields() // [private int my.Demo.archived, private int my.Demo.demo]
println Demo.fieldNames() // [archived, demo]

Related

Is there a way to check if a method is called in in a 3rd party library in java? [duplicate]

I need to get a list of all caller methods for a method of interest for me in Java. Is there a tool that can help me with this?
Edit: I forgot to mention that I need to do this from a program. I'm usig Java Pathfinder and I want to run it an all the methods that call my method of interest.
For analyzing bytecode, I would recommend ASM. Given a list of Classes to analyze, a visitor can be made which finds the method calls you're interested in. One implementation which analyses classes in a jar file is below.
Note that ASM uses internalNames with '/' instead of '.' as a separator. Specify the target method as a standard declaration without modifiers.
For example, to list methods that could be calling System.out.println("foo") in the java runtime jar:
java -cp "classes;asm-3.1.jar;asm-commons-3.1.jar" App \
c:/java/jdk/jre/lib/rt.jar \
java/io/PrintStream "void println(String)"
Edit: source and line numbers added: Note that this only indicates the last target method invocation per calling method - the original q only wanted to know which methods. I leave it as an exercise for the reader to show line numbers of the calling method declaration, or the line numbers of every target invocation, depending on what you're actually after. :)
results in:
LogSupport.java:44 com/sun/activation/registries/LogSupport log (Ljava/lang/String;)V
LogSupport.java:50 com/sun/activation/registries/LogSupport log (Ljava/lang/String;Ljava/lang/Throwable;)V
...
Throwable.java:498 java/lang/Throwable printStackTraceAsCause (Ljava/io/PrintStream;[Ljava/lang/StackTraceElement;)V
--
885 methods invoke java/io/PrintStream println (Ljava/lang/String;)V
source:
public class App {
private String targetClass;
private Method targetMethod;
private AppClassVisitor cv;
private ArrayList<Callee> callees = new ArrayList<Callee>();
private static class Callee {
String className;
String methodName;
String methodDesc;
String source;
int line;
public Callee(String cName, String mName, String mDesc, String src, int ln) {
className = cName; methodName = mName; methodDesc = mDesc; source = src; line = ln;
}
}
private class AppMethodVisitor extends MethodAdapter {
boolean callsTarget;
int line;
public AppMethodVisitor() { super(new EmptyVisitor()); }
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
if (owner.equals(targetClass)
&& name.equals(targetMethod.getName())
&& desc.equals(targetMethod.getDescriptor())) {
callsTarget = true;
}
}
public void visitCode() {
callsTarget = false;
}
public void visitLineNumber(int line, Label start) {
this.line = line;
}
public void visitEnd() {
if (callsTarget)
callees.add(new Callee(cv.className, cv.methodName, cv.methodDesc,
cv.source, line));
}
}
private class AppClassVisitor extends ClassAdapter {
private AppMethodVisitor mv = new AppMethodVisitor();
public String source;
public String className;
public String methodName;
public String methodDesc;
public AppClassVisitor() { super(new EmptyVisitor()); }
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
className = name;
}
public void visitSource(String source, String debug) {
this.source = source;
}
public MethodVisitor visitMethod(int access, String name,
String desc, String signature,
String[] exceptions) {
methodName = name;
methodDesc = desc;
return mv;
}
}
public void findCallingMethodsInJar(String jarPath, String targetClass,
String targetMethodDeclaration) throws Exception {
this.targetClass = targetClass;
this.targetMethod = Method.getMethod(targetMethodDeclaration);
this.cv = new AppClassVisitor();
JarFile jarFile = new JarFile(jarPath);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().endsWith(".class")) {
InputStream stream = new BufferedInputStream(jarFile.getInputStream(entry), 1024);
ClassReader reader = new ClassReader(stream);
reader.accept(cv, 0);
stream.close();
}
}
}
public static void main( String[] args ) {
try {
App app = new App();
app.findCallingMethodsInJar(args[0], args[1], args[2]);
for (Callee c : app.callees) {
System.out.println(c.source+":"+c.line+" "+c.className+" "+c.methodName+" "+c.methodDesc);
}
System.out.println("--\n"+app.callees.size()+" methods invoke "+
app.targetClass+" "+
app.targetMethod.getName()+" "+app.targetMethod.getDescriptor());
} catch(Exception x) {
x.printStackTrace();
}
}
}
Edit: the original question was edited to indicate a runtime solution was needed - this answer was given before that edit and only indicates how to do it during development.
If you are using Eclipse you can right click the method and choose "Open call hierarchy" to get this information.
Updated after reading comments: Other IDEs support this as well in a similar fashion (at least Netbeans and IntelliJ do)
Annotate the method with #Deprecated ( or tag it with #deprecated ), turn on deprecation warnings, run your compile and see which warnings get triggered.
The run your compile bit can be done either by invoking an external ant process or by using the Java 6 compiler API.
right click on method
Go to references and (depending on your requirement)
choose workspace/project/Hierarchy.
This pops up a panel that shows all references to this functions. Eclipse FTW !
In eclipse, highlight the method name and then Ctrl+Shift+G
There isn't a way to do this (programmatically) via the Java reflection libraries - you can't ask a java.lang.reflect.Method "which methods do you call?"
That leaves two other options I can think of:
Static analysis of the source code. I'm sure this is what the Eclipse Java toolset does - you could look at the Eclipse source behind the JDT, and find what it does when you ask Eclipse to "Find References" to a method.
Bytecode analysis. You could inspect the bytecode for calls to the method. I'm not sure what libraries or examples are out there to help with this - but I can't imagine that something doesn't exist.
Yes, most modern IDE:s will let you either search for usages of a method or variable. Alternatively, you could use a debugger and set a trace point on the method entry, printing a stack trace or whatever every time the method is invoked.
Finally, you could use some simple shell util to just grep for the method, such as
find . -name '*.java' -exec grep -H methodName {} ;
The only method that will let you find invokations made through some reflection method, though, would be using the debugger.
I made a small example using #Chadwick's one. It's a test that assesses if calls to getDatabaseEngine() are made by methods that implement #Transaction.
/**
* Ensures that methods that call {#link DatabaseProvider#getDatabaseEngine()}
* implement the {#link #Transaction} annotation.
*
* #throws Exception If something occurs while testing.
*/
#Test
public void ensure() throws Exception {
final Method method = Method.getMethod(
DatabaseEngine.class.getCanonicalName() + " getDatabaseEngine()");
final ArrayList<java.lang.reflect.Method> faultyMethods = Lists.newArrayList();
for (Path p : getAllClasses()) {
try (InputStream stream = new BufferedInputStream(Files.newInputStream(p))) {
ClassReader reader = new ClassReader(stream);
reader.accept(new ClassAdapter(new EmptyVisitor()) {
#Override
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
return new MethodAdapter(new EmptyVisitor()) {
#Override
public void visitMethodInsn(int opcode, String owner, String nameCode, String descCode) {
try {
final Class<?> klass = Class.forName(Type.getObjectType(owner).getClassName());
if (DatabaseProvider.class.isAssignableFrom(klass) &&
nameCode.equals(method.getName()) &&
descCode.equals(method.getDescriptor())) {
final java.lang.reflect.Method method = klass.getDeclaredMethod(name,
getParameters(desc).toArray(new Class[]{}));
for (Annotation annotation : method.getDeclaredAnnotations()) {
if (annotation.annotationType().equals(Transaction.class)) {
return;
}
}
faultyMethods.add(method);
}
} catch (Exception e) {
Throwables.propagate(e);
}
}
};
}
}, 0);
}
}
if (!faultyMethods.isEmpty()) {
fail("\n\nThe following methods must implement #Transaction because they're calling getDatabaseEngine().\n\n" + Joiner.on("\n").join
(faultyMethods) + "\n\n");
}
}
/**
* Gets all the classes from target.
*
* #return The list of classes.
* #throws IOException If something occurs while collecting those classes.
*/
private List<Path> getAllClasses() throws IOException {
final ImmutableList.Builder<Path> builder = new ImmutableList.Builder<>();
Files.walkFileTree(Paths.get("target", "classes"), new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
if (file.getFileName().toString().endsWith(".class")) {
builder.add(file);
}
return FileVisitResult.CONTINUE;
}
});
return builder.build();
}
/**
* Gets the list of parameters given the description.
*
* #param desc The method description.
* #return The list of parameters.
* #throws Exception If something occurs getting the parameters.
*/
private List<Class<?>> getParameters(String desc) throws Exception {
ImmutableList.Builder<Class<?>> obj = new ImmutableList.Builder<>();
for (Type type : Type.getArgumentTypes(desc)) {
obj.add(ClassUtils.getClass(type.getClassName()));
}
return obj.build();
}
1)In eclipse it is ->right click on the method and select open call hierarchy or CLT+ALT+H
2)In jdeveloper it is -> right click on the method and select calls or ALT+SHIFT+H
The closest that I could find was the method described in this StackOverflow questions selected answer.check this out
You can do this with something in your IDE such as "Find Usages" (which is what it is called in Netbeans and JDeveloper). A couple of things to note:
If your method implements a method from an interface or base class, you can only know that your method is POSSIBLY called.
A lot of Java frameworks use Reflection to call your method (IE Spring, Hibernate, JSF, etc), so be careful of that.
On the same note, your method could be called by some framework, reflectively or not, so again be careful.

Is it possible to get StackOverflowError without recursion?

I have a task to get "StackOverflowError" in java without using -Xss and recursion. I really don't have ideas... Only some nonsense like generating huge java class at runtime, compile it and invoke...
Java stores primitive types on the stack. Objects created in local scope are allocated on the heap, with the reference to them on the stack.
You can overflow the stack without recursion by allocating too many primitive types in method scope. With normal stack size settings, you would have to allocate an excessive number of variables to overflow.
Here is the implementation of Eric J. idea of generating excessive number of local variables using javassist library:
class SoeNonRecursive {
static final String generatedMethodName = "holderForVariablesMethod";
#SneakyThrows
Class<?> createClassWithLotsOfLocalVars(String generatedClassName, final int numberOfLocalVarsToGenerate) {
ClassPool pool = ClassPool.getDefault();
CtClass generatedClass = pool.makeClass(generatedClassName);
CtMethod generatedMethod = CtNewMethod.make(getMethodBody(numberOfLocalVarsToGenerate), generatedClass);
generatedClass.addMethod(generatedMethod);
return generatedClass.toClass();
}
private String getMethodBody(final int numberOfLocalVarsToGenerate) {
StringBuilder methodBody = new StringBuilder("public static long ")
.append(generatedMethodName).append("() {")
.append(System.lineSeparator());
StringBuilder antiDeadCodeEliminationString = new StringBuilder("long result = i0");
long i = 0;
while (i < numberOfLocalVarsToGenerate) {
methodBody.append(" long i").append(i)
.append(" = ").append(i).append(";")
.append(System.lineSeparator());
antiDeadCodeEliminationString.append("+").append("i").append(i);
i++;
}
antiDeadCodeEliminationString.append(";");
methodBody.append(" ").append(antiDeadCodeEliminationString)
.append(System.lineSeparator())
.append(" return result;")
.append(System.lineSeparator())
.append("}");
return methodBody.toString();
}
}
and tests:
class SoeNonRecursiveTest {
private final SoeNonRecursive soeNonRecursive = new SoeNonRecursive();
//Should be different for every case, or once generated class become
//"frozen" for javassist: http://www.javassist.org/tutorial/tutorial.html#read
private String generatedClassName;
#Test
void stackOverflowWithoutRecursion() {
generatedClassName = "Soe1";
final int numberOfLocalVarsToGenerate = 6000;
assertThrows(StackOverflowError.class, () -> soeNonRecursive
.createClassWithLotsOfLocalVars(generatedClassName, numberOfLocalVarsToGenerate));
}
#SneakyThrows
#Test
void methodGeneratedCorrectly() {
generatedClassName = "Soe2";
final int numberOfLocalVarsToGenerate = 6;
Class<?> generated = soeNonRecursive.createClassWithLotsOfLocalVars(generatedClassName, numberOfLocalVarsToGenerate);
//Arithmetic progression
long expected = Math.round((numberOfLocalVarsToGenerate - 1.0)/2 * numberOfLocalVarsToGenerate);
long actual = (long) generated.getDeclaredMethod(generatedMethodName).invoke(generated);
assertEquals(expected, actual);
}
}
EDIT:
The answer is incorrect, because it is one type of recursion. It is called indirect recursion https://en.wikipedia.org/wiki/Recursion_(computer_science)#Indirect_recursion.
I think the simplest way to do this without recursion is the following:
import java.util.LinkedList;
import java.util.List;
interface Handler {
void handle(Chain chain);
}
interface Chain {
void process();
}
class FirstHandler implements Handler {
#Override
public void handle(Chain chain) {
System.out.println("first handler");
chain.process();
}
}
class SecondHandler implements Handler {
#Override
public void handle(Chain chain) {
System.out.println("second handler");
chain.process();
}
}
class Runner implements Chain {
private List<Handler> handlers;
private int size = 5000; // change this parameter to avoid stackoverflowerror
private int n = 0;
public static void main(String[] args) {
Runner runner = new Runner();
runner.setHandlers();
runner.process();
}
private void setHandlers() {
handlers = new LinkedList<>();
int i = 0;
while (i < size) {
// there can be different implementations of handler interface
handlers.add(new FirstHandler());
handlers.add(new SecondHandler());
i += 2;
}
}
public void process() {
if (n < size) {
Handler handler = handlers.get(n++);
handler.handle(this);
}
}
}
At first glance this example looks a little crazy, but it's not as unrealistic as it seems.
The main idea of this approach is the chain of responsibility pattern. You can reproduce this exception in real life by implementing chain of responsibility pattern. For instance, you have some objects and every object after doing some logic call the next object in chain and pass the results of his job to the next one.
You can see this in java filter (javax.servlet.Filter).
I don't know detailed mechanism of working this class, but it calls the next filter in chain using doFilter method and after all filters/servlets processing request, it continue working in the same method below doFilter.
In other words it intercepts request/response before servlets and before sending response to a client.It is dangerous piece of code because all called methods are in the same stack at the same thread. Thus, it may initiate stackoverflow exception if the chain is too big or you call doFilter method on deep level that also provide the same situation. Perhaps, during debugging you might see chain of calls
in one thread and it potentially can be the cause of stackoverflowerror.
Also you can take chain of responsibility pattern example from links below and add collection of elements instead of several and you also will get stackoverflowerror.
Links with the pattern:
https://www.journaldev.com/1617/chain-of-responsibility-design-pattern-in-java
https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
I hope it was helpful for you.
Since the question is very interesting, I have tried to simplify the answer of hide :
public class Stackoverflow {
static class Handler {
void handle(Chain chain){
chain.process();
System.out.println("yeah");
}
}
static class Chain {
private List<Handler> handlers = new ArrayList<>();
private int n = 0;
private void setHandlers(int count) {
int i = 0;
while (i++ < count) {
handlers.add(new Handler());
}
}
public void process() {
if (n < handlers.size()) {
Handler handler = handlers.get(n++);
handler.handle(this);
}
}
}
public static void main(String[] args) {
Chain chain = new Chain();
chain.setHandlers(10000);
chain.process();
}
}
It's important to note that if stackoverflow occurs, the string "yeah" will never be output.
Of course we can do it :) . No recursion at all!
public static void main(String[] args) {
throw new StackOverflowError();
}
Looking at this answer below, not sure if this works for Java, but sounds like you can declare an array of pointers? Might be able to achieve Eric J's idea without requiring a generator.
Is it on the Stack or Heap?
int* x[LARGENUMBER]; // The addresses are held on the stack
int i; // On the stack
for(i = 0; i < LARGENUMBER; ++i)
x[i] = malloc(sizeof(int)*10); // Allocates memory on the heap

Need design suggestions for nested conditions

I need to write the logic with many conditions(up to 30 conditions) in one set of rule with many if else conditions and it could end in between or after all the conditions.
Here is the sample code I have tried with some possible scenario. This gives me result but doesn't look good and any minor miss in one condition would take forever to track.
What I have tried so far is, Take out common conditions and refactored to some methods. Tried creating interface with conditions and various set would implement it.
If you have any suggestion to design this, would help me. Not looking for detailed solution but even a hint would be great.
private Boolean RunCondition(Input input) {
Boolean ret=false;
//First if
if(input.a.equals("v1")){
//Somelogic1();
//Second if
if(input.b.equals("v2"))
//Third if
if(input.c >1)
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(input.d.equals("Z1"))
System.out.println("Passed 1");
// Fourth Else
else{
System.out.println("Failed at fourth");
}
//Third Else
else{
if(input.aa.equals("v2"))
System.out.println("Failed at third");
}
//Second Else
else{
if(input.bb.equals("v2"))
System.out.println("Failed at second");
}
}
//First Else
else{
if(input.cc.equals("v2"))
System.out.println("Failed aat first");
}
return ret;
}
public class Input {
String a;
String b;
int c;
String d;
String e;
String aa;
String bb;
String cc;
String dd;
String ee;
}
The flow is complicated because you have a normal flow, plus many possible exception flows when some of the values are exceptional (e.g. invalid).
This is a perfect candidate to be handled using a try/catch/finally block.
Your program can be rewritten into following:
private Boolean RunCondition(Input input) {
Boolean ret=false;
try {
//First if
if(!input.a.equals("v1")) {
throw new ValidationException("Failed aat first");
}
//Somelogic1();
//Second if
if(!input.b.equals("v2")) {
throw new ValidationException("Failed at second");
}
//Somelogic2()
//Third if
if(input.c<=1) {
throw new ValidationException("Failed at third");
}
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(!input.d.equals("Z1")) {
throw new ValidationException("Failed at fourth");
}
System.out.println("Passed 1");
} catch (ValidationException e) {
System.out.println(e.getMessage());
}
return ret;
}
Where you can define your own ValidationException (like below), or you can reuse some of the existing standard exception such as RuntimeException
class ValidationException extends RuntimeException {
public ValidationException(String arg0) {
super(arg0);
// TODO Auto-generated constructor stub
}
/**
*
*/
private static final long serialVersionUID = 1L;
}
You can read more about this in
https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html
Make a separate class for the condition:
package com.foo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App
{
static class Condition<T> {
final int idx;
final T compareValue;
public Condition(final int idx, final T compareValue) {
this.idx = idx;
this.compareValue = compareValue;
}
boolean satisfies(final T other) {
return other.equals(compareValue);
}
int getIdx() {
return idx;
}
}
public static void main( String[] args )
{
final List<Condition<String>> conditions = new ArrayList<Condition<String>>();
conditions.add(new Condition<String>(1, "v1"));
conditions.add(new Condition<String>(2, "v2"));
final List<String> inputs = new ArrayList<String>(Arrays.asList("v1", "xyz"));
boolean ret = true;
for (int i = 0; i < inputs.size(); i++) {
if (!conditions.get(i).satisfies(inputs.get(i)))
{
System.out.println("failed at " + conditions.get(i).getIdx());
ret = false;
break;
}
}
System.out.println("ret=" + ret);
}
}
#leeyuiwah's answer has a clear structure of the conditional logic, but exceptions aren't the right tool for the job here.
You shouldn't use exceptions to cope with non-exceptional conditions. For one thing, exceptions are really expensive to construct, because you have to walk all the way up the call stack to construct the stack trace; but you don't need the stack trace at all.
Check out Effective Java 2nd Ed Item 57: "Use exceptions only for exceptional conditions" for a detailed discussion of why you shouldn't use exceptions like this.
A simpler option is to define a little helper method:
private static boolean printAndReturnFalse(String message) {
System.out.println(message);
return false;
}
Then:
if(!input.a.equals("v1")) {
return printAndReturnFalse("Failed aat first");
}
// etc.
which I think is a simpler; and it'll be a lot faster.
Think of each rule check as an object, or as a Strategy that returns whether or not the rule passes. Each check should implement the same IRuleCheck interface and return a RuleCheckResult, which indicates if the check passed or the reason for failure.
public interface IRuleCheck
{
public RuleCheckResult Check(Input input);
public String Name();
}
public class RuleCheckResult
{
private String _errorMessage;
public RuleCheckResult(){}//All Good
public RuleCheckResult(String errorMessage)
{
_errorMessage = errorMessage;
}
public string ErrorMessage()
{
return _errorMessage;
}
public Boolean Passed()
{
return _errorMessage == null || _errorMessage.isEmpty();
}
}
public class CheckOne implements IRuleCheck
{
public RuleCheckResult Check(Input input)
{
if (input.d.equals("Z1"))
{
return new RuleCheckResult();//passed
}
return new RuleCheckResult("d did not equal z1");
}
public String Name();
}
Then you can simply build a list of rules and loop through them,
and either jump out when one fails, or compile a list of failures.
for (IRuleCheck check : checkList)
{
System.out.println("checking: " + check.Name());
RuleCheckResult result = check.Check(input);
if(!result.Passed())
{
System.out.println("FAILED: " + check.Name()+ " - " + result.ErrorMessage());
//either jump out and return result or add it to failure list to return later.
}
}
And the advantage of using the interface is that the checks can be as complicated or simple as necessary, and you can create arbitrary lists for checking any combination of rules in any order.

Ensure single instance of a spring managed bean

I have created a spring aspect to handle Retry mechanism. I have also created a Retry annotation.
Following is the code for Retry annotation and an aspect which processes this annotation.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Retry {
/**
* List of exceptions for which we need to retry method invocation.
*
* #return Array of classes.
*/
Class<?>[] exceptions();
/**
* Number of retries. Default is 3.
*
* #return Number of retires.
*/
int retries() default 3;
/**
* Back of period in ms. Default is 1000 ms.
*
* #return Back off Period.
*/
int backOffPeriod() default 1000;
}
#Aspect
public class RetryInterceptor implements Ordered {
private static final RetryInterceptor instance = new RetryInterceptor();
private RetryInterceptor() {
}
private static final Log logger = LogFactory.getLog(RetryInterceptor.class);
private int order = 100;
#Around("#annotation(retry)")
public Object performOperation(ProceedingJoinPoint pjp, Retry retry) throws Throwable {
Class<?>[] exceptionClasses = retry.exceptions();
Assert.notEmpty(exceptionClasses, "Exception classes cannot be empty.");
int retries = retry.retries();
if (logger.isInfoEnabled()) {
logger.info("Attempting to call " + pjp.toShortString() + " with potential for " + getExceptionClasses(exceptionClasses)
+ " with maximum " + retries + " retries");
}
int numAttempts = 0;
do {
try {
return pjp.proceed();
} catch (Throwable ex) {
// if the exception is not what we're looking for, pass it through
boolean canThrowException = true;
for (Class<?> exceptionClass : exceptionClasses) {
if (exceptionClass.isAssignableFrom(ex.getClass())) {
canThrowException = false;
break;
}
}
// A non-configured exception was found.
if (canThrowException) {
throw ex;
}
// we caught the configured exception, retry unless we've reached the maximum
if (++numAttempts > retries) {
logger.warn("Caught " + ex.getClass().getCanonicalName() + " and exceeded maximum retries (" + retries
+ "), rethrowing.");
throw ex;
}
if (logger.isInfoEnabled()) {
logger.info("Caught " + ex.getClass().getCanonicalName() + " and will retry, attempts: " + numAttempts);
}
}
sleep(retry.backOffPeriod());
} while (numAttempts <= retries);
// this will never execute - we will have either successfully returned or re-thrown an
// exception
return null;
}
#Override
public int getOrder() {
return order;
}
private String getExceptionClasses(Class<?>[] classes) {
StringBuilder builder = new StringBuilder();
builder.append(classes[0].getCanonicalName());
for (int i = 1; i < classes.length; i++) {
builder.append(", ").append(classes[i].getCanonicalName());
}
return builder.toString();
}
public static RetryInterceptor getInstance() {
return instance;
}
// Better than Thread.sleep().
public void sleep(long backOffPeriod) throws InterruptedException {
Object mutex = new Object();
synchronized (mutex) {
mutex.wait(backOffPeriod);
}
}
}
To enable the annotation, I need to instantiate the RetryInterceptor class. I want to ensure that for a given context there is only one instance of this object. If for some reason multiple objects are created my advice is applied that many times. How can I totally ensure that there will always be 1 instance?
I found a way to do this :) Ref: Going Beyond DI
I registered a BeanDefinitionRegistryPostProcessor in my root context, this will ensure that there is only one BeanDefinition of my desired class.
package test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import com.xx.xx.xx.xx.xx.RetryInterceptor;
public class TestBeanFacotryPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
String[] definitionNames = registry.getBeanDefinitionNames();
for (int i = 0, j = 0; i < definitionNames.length; i++) {
Class<?> clazz;
try {
clazz = Class.forName(registry.getBeanDefinition(definitionNames[i]).getBeanClassName());
if (RetryInterceptor.class == clazz && j++ > 0) {
registry.removeBeanDefinition(definitionNames[i]);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
There will ever only be one instance as its a spring managed bean with the default scope of singleton. You have some singleton type stuff at the top of your class (like where you create your new instance statically etc)... this is not needed. An aspect is just a bean like any other so code it asuch. If you want to be sure, put in a PostContruct method with some logging like 'Initiating aspect' or something and you will see it only prints to your logs once.
if someone can create second bean of your type, why you are don't want to check someone creates another aspect with same logic? I think your approach is erroneous by design.
you can implement ApplicationContextAware interface and check there, that only one bean of your class present in context and throw exception if it's not true, but I'm not sure that this will work if you have context hierarchy.

Is there a way to take an argument in a callable method?

I have created a piece of code which takes an IP address (from main method in another class) and then loops through a range of IP addresses pinging each one as it goes. I have a GUI front end on this and it was crashing (hence why I've done the multithreading. My problem is I can no longer take the IP address as an argument in my ping code as its callable. I've searched all over for this and cant seem to find a way to get round this. Is there a way for a callable method to take arguments? If not is there any other way to accomplish what I'm trying to do?
sample of my code:
public class doPing implements Callable<String>{
public String call() throws Exception{
String pingOutput = null;
//gets IP address and places into new IP object
InetAddress IPAddress = InetAddress.getByName(IPtoPing);
//finds if IP is reachable or not. a timeout timer of 3000 milliseconds is set.
//Results can vary depending on permissions so cmd method of doing this has also been added as backup
boolean reachable = IPAddress.isReachable(1400);
if (reachable){
pingOutput = IPtoPing + " is reachable.\n";
}else{
//runs ping command once on the IP address in CMD
Process ping = Runtime.getRuntime().exec("ping " + IPtoPing + " -n 1 -w 300");
//reads input from command line
BufferedReader in = new BufferedReader(new InputStreamReader(ping.getInputStream()));
String line;
int lineCount = 0;
while ((line = in.readLine()) != null) {
//increase line count to find part of command prompt output that we want
lineCount++;
//when line count is 3 print result
if (lineCount == 3){
pingOutput = "Ping to " + IPtoPing + ": " + line + "\n";
}
}
}
return pingOutput;
}
}
IPtoPing used to be the argument that was taken.
You can't pass it as the argument to call() because the method signature doesn't allow it.
However, you can pass the necessary information as a constructor argument; e.g.
public class DoPing implements Callable<String>{
private final String ipToPing;
public DoPing(String ipToPing) {
this.ipToPing = ipToPing;
}
public String call() throws SomeException {
InetAddress ipAddress = InetAddress.getByName(ipToPing);
....
}
}
(I've corrected a couple of egregious code style violations!!)
There are ways to eliminate some of the "boilerplate" coding in the above (see some of the other answers). In this case we are talking about 4 lines of code (in a ~40 line class), so I am not convinced that it is worth the effort. (But hey, it is your code.)
Alternatively, you could:
declare DoPing as an inner class (or a lambda) and have it refer to a final ipToPing in the enclosing scope, or
add a setIpToPing(String ipToPing) method.
(The last allows a DoPing object to be reused, but the downside is that you will need to synchronize to access it thread-safely.)
Adding to Jarle's answer -- in case you create Callable as instance of anonymous class, you can use final field outside of anonymous class for passing data into the instance:
final int arg = 64;
executor.submit(new Callable<Integer>() {
public Integer call() throws Exception {
return arg * 2;
}
});
You can't pass arguments to call() because the method signature doesn't allow it but here is at least one way to work around that by
defining an abstract class that wraps/implements Callable and
implementing a setter to "inject" a result into call()
Define an abstract class:
import java.util.concurrent.Callable;
public abstract class Callback<T> implements Callable<Void> {
T result;
void setResult (T result) {
this.result = result;
}
public abstract Void call ();
}
Define the method that should fire the callback:
public void iWillFireTheCallback (Callback callback) {
// You could also specify the signature like so:
// Callback<Type of result> callback
// make some information ("the result")
// available to the callback function:
callback.setResult("Some result");
// fire the callback:
callback.call();
}
In the place where you want to call iWillFireTheCallback:
Define the callback function (even possible inside methods):
class MyCallback extends Callback {
#Override
public Void call () {
// this is the actual callback function
// the result variable is available right away:
Log.d("Callback", "The result is: " + result);
return null;
}
}
And then call iWillFireTheCallback while passing in the callback:
iWillFireTheCallback(new MyCallback());
When you create the doPing-class (should be captial letter in class name), send in the ip-address in the constructor. Use this ip-address in the call-method.
Put some (final) fields in your doPing class, and a constructor that initializes them, then pass the values you want to use in call() to the constructor of doPing:
public class DoPing implements Callable<String> {
private final String ipToPing;
public DoPing(String ip) {
this.ipToPing = ip;
}
public String call() {
// use ipToPing
}
}
I know it is super-late to answer this, considering it is more than 8 years old but active 15 days(!) ago, I feel this will still help someone using Java 8 and above.
PS, it is simply a syntactic sugar of Victor Sorokin's answer possible through lambdas.
public static Callable<String> generateCallableWithArg(final String input) {
return () -> {
Thread.sleep(5000); // someExpensiveOperationHere
return "Return Value of " + input; //input can be used here
};
}
Also, we can write a static helper method that can convert a Function to Callable.
public class CallableGenerator {
public static <T,V> Callable<V> getCallableFromFunction(Function<T, V> function, T input) {
return () -> function.apply(input);
}
}
This can be used as
Callable<Integer> iAmCallable = CallableGenerator.getCallableFromFunction(i1 -> i1 * 2, 3);
You have to defien a property such as ipAddress and its accessor method. and passing its value in constructor or by setter method. In doPing class use ipAddress property.
class DoPing/* In java all classes start with capital letter */implements Callable<String>
{
private String ipAddress;
public String getIpAddress()
{
return ipAddress;
}
public void setIpAddress(String ipAddress)
{
this.ipAddress = ipAddress;
}
/*
* Counstructor
*/
public DoPing(String ipAddress )
{
this.ipAddress = ipAddress;
}
#Override
public String call() throws Exception
{
// your logic
}
}
It is not always possible to make reference to (effectively) final variable to use its value as "argument", but you can make comfy general solution by yourself. First define this functional interface:
#FunctionalInteface
interface CallableFunction<T, R> {
public abstract R call(T arg) throws Exception;
public static <T, R> Callable<R> callable(CallableFunction<T, R> cf, T arg) {
return () -> cf.call(arg);
}
}
This functional interface provides static method callable that creates a Callable instance, which simply calls call(T) with provided argument (of type T). Then you need you DoPing class to implement CallableFunction like this:
public class DoPing implements CallableFunction<String, String> {
#Override
public String call(final String ipToPing) throws Exception {
final var ipAddress = InetAddress.getByName(ipToPing);
final var reachable = ipAddress.isReachable(1400);
String pingOutput = null;
if (reachable) {
pingOutput = ipToPing + " is reachable.\n";
}
else {
final var ping = Runtime.getRuntime().exec("ping " + ipToPing + " -n 1 -w 300");
try (var in = new BufferedReader(new InputStreamReader(ping.getInputStream()))) {
String line;
for (int lineCount = 1; (line = in.readLine()) != null; ++lineCount) {
if (lineCount == 3) {
pingOutput = "Ping to " + ipToPing + ": " + line + "\n";
break;
}
}
}
}
return pingOutput;
}
Here we changed call signature to accept String argument and also now it implements CallableFunction and not Callable as before. Other changes are minor, but it's worth mentioning, that we prevented resource leak with use of try-with-resource on BufferedReader and also break has been added to input collecting loop (change from while to for) to terminate as quickly, as possible.
Now you can use the code e.g. like this:
final var ping = CallableFunction.callable(new DoPing(), "127.0.0.1");
final var task = new FutureTask<>(ping);
new Thread(task).start();
System.out.println(task.get(20, TimeUnit.SECONDS));
You can also reuse CallableFunction in other cases, when you needed it.

Categories