Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: check if a class exists and call a specific method if it exists

Is there a way to do the following? Check if a class exists (in the same package) and if it does exist, check if a particular method exists, and if so, calling it?

Say that I have class X. In some method of class X, I want to do the following:

if (class Y exists) { //Maybe use Class.forName("Y")?
  if ( Y has method a(String, String) ) {
    call Y.a("hello", "world");
  }
}

Is such a thing possible? And is doing such a thing reasonable? Thanks.

like image 643
HikeTakerByRequest Avatar asked Feb 17 '17 08:02

HikeTakerByRequest


People also ask

How do I check if a class object exists?

Method 1: Using the typeof operator The typeof operator returns the type of the variable on which it is called as a string. The return string for any object that does not exist is “undefined”. This can be used to check if an object exists or not, as a non-existing object will always return “undefined”.

How do you check if an object of a class exists in Java?

forName() We can check for the existence of a class using Java Reflection, specifically Class. forName().

What is class forName in Java with example?

forName(String name, boolean initialize, ClassLoader loader) method returns the Class object associated with the class or interface with the given string name, using the given class loader. The specified class loader is used to load the class or interface.


5 Answers

Is such a thing possible? And is doing such a thing reasonable? Thanks.

Of course it is possible.
If you develop a program or a library that has to discover dynamically some classes, it is a very reasonable thing.
If it is not the case, it could not be.


If your need makes sense, you should ask you an additional question : should you invoke a static or instance method ?

Here is a sample example with both solutions :

ReflectionClass that contains the logic using reflection :

import java.lang.reflect.Method;

public class ReflectionCalls {
    public static void main(String[] args) {
        new ReflectionCalls();
    }

    public ReflectionCalls() {
        callMethod(true);
        callMethod(false);
    }

    private void callMethod(boolean isInstanceMethod) {

        String className = "DiscoveredClass";
        String staticMethodName = "methodStatic";
        String instanceMethodName = "methodInstance";
        Class<?>[] formalParameters = { int.class, String.class };
        Object[] effectiveParameters = new Object[] { 5, "hello" };
        String packageName = getClass().getPackage().getName();

        try {
            Class<?> clazz = Class.forName(packageName + "." + className);

            if (!isInstanceMethod) {
                Method method = clazz.getMethod(staticMethodName, formalParameters);
                method.invoke(null, effectiveParameters);
            }

            else {
                Method method = clazz.getMethod(instanceMethodName, formalParameters);
                Object newInstance = clazz.newInstance();
                method.invoke(newInstance, effectiveParameters);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

DiscoveredClass (the class we manipulate in the example)

  package reflectionexp;
    
    public class DiscoveredClass {
        
        public static void methodStatic(int x, String string) {
            System.out.println("static method with " + x + " and " + string);
        }
    
        public void methodInstance(int x, String string) {
            System.out.println("instance method with " + x + " and " + string);
        }
    
    }

Output :

instance method with 5 and hello

static method with 5 and hello

like image 155
davidxxx Avatar answered Oct 19 '22 22:10

davidxxx


Yes, this can be done. I've created a Test class in the same Package as the current class.

import java.lang.reflect.Method;

public class Sample {

    public static void main(String[] args) {
        Class<?> clazz = null;
        try {
            clazz = Class.forName("Test");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (clazz == null) {
            System.out.println("class not found. Go eat some waffles and correct the name");
            return;
        }

        Method m = null;
        try {
            m = clazz.getMethod("foo", null);
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (m == null) {
            System.out.println("method not found. Go eat some waffles and correct the name");
            return;
        }
        Test t;
        try {
            t = (Test) clazz.newInstance();
            m.invoke(t, null);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }

}

public class Test {

    static {
        System.out.println("test...");
    }

    public void foo() {
        System.out.println("foo");
    }
}

O/P :

test...
foo
like image 38
TheLostMind Avatar answered Oct 19 '22 23:10

TheLostMind


You can use Class.forName:

try {
    Class yourClass = Class.forName( "classname" );
    Object o = yourClass.newInstance();
} catch( ClassNotFoundException e ) {
    //Throw error or whatever
}

To check if a method exists you could use the NoSuchMethodError e in a try/catch

like image 30
Luud van Keulen Avatar answered Oct 19 '22 22:10

Luud van Keulen


You can do this using reflection, however it isnt really practical unless you are trying to access classes that potentially will not be present at runtime or if you are trying to access private or hidden fields. Example below.

public static void reflectionDemo(){

    //Here we attempt to get the common URI class
    //If it is found, we attempt to get the create method
    //We then invoke the create method and print the class name of the result.

    try {
        Class<?> uriClass = Class.forName("java.net.URI");
        //getMethod(String name, Class<?>... args);
        java.lang.reflect.Method create = uriClass.getMethod("create", String.class);

        //The first parameter is null because this is a static method.
        //invoke(Object target, Object... args);
        System.out.println(create.invoke(null, "some/uri").getClass());
        //Will print class java.net.URI

    } catch (ClassNotFoundException e) {
        // If class doesnt exist
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        // If method doesnt exist
        e.printStackTrace();
    } catch (SecurityException e) {
        // See Javadoc
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // From invoke
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        // From invoke
        e.printStackTrace();
    } catch (java.lang.reflect.InvocationTargetException e) {
        // From invoke
        e.printStackTrace();
    }
}
like image 39
d_scalzi Avatar answered Oct 19 '22 23:10

d_scalzi


To find whether a class exists, you can use the forName() method on Class. To find whether a method exists, you can use the getMethod() method on Class. Documentation here:

https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#forName(java.lang.String) https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getMethod(java.lang.String,%20java.lang.Class...)

For your class problem, you'd want to use code like:

try {
    Class.forName("Y");
}
catch (ClassNotFoundException e) {

}

For your method problem, you'd want to use code like:

try {
    Class.getMethod(a);
}
catch (NoSuchMethodException e) {

}
like image 35
davidqshull Avatar answered Oct 19 '22 23:10

davidqshull