6

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.

HikeTakerByRequest
  • 333
  • 1
  • 2
  • 15
  • Whether it's reasonable depends on your requirements. In most cases it's not reasonable. In the rare cases it *is* reasonable, you would most likely understand exactly what you're doing and why you're doing it. – Kayaman Feb 17 '17 at 09:41

6 Answers6

7

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

Community
  • 1
  • 1
davidxxx
  • 125,838
  • 23
  • 214
  • 215
3

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
TheLostMind
  • 35,966
  • 12
  • 68
  • 104
  • Most of that makes sense but in this case we can't typecast to class Test because it may not exist, no? As in, this code wouldn't compile I think. – HikeTakerByRequest Feb 18 '17 at 05:02
2

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

Luud van Keulen
  • 1,204
  • 12
  • 38
1

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();
    }
}
d_scalzi
  • 425
  • 4
  • 13
1

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) {

}
davidqshull
  • 126
  • 1
  • 5
0

You can check if the Class exists with Class.forName("classname");

See this SO question: Check if class exists somewhere in package

If a method exists can be catched with NoSuchMethodError in your try/catch.

See this SO question: Check if method exists at Runtime in Java

try {
  Object object = Class.forName("Y").newInstance();
  object.a(String, String);
} catch( ClassNotFoundException | NoSuchMethodError ex) {
  //do Something else
}
Community
  • 1
  • 1
milt_on
  • 527
  • 1
  • 9
  • 20