How would one go about checking to see if a method exists for a class in Java? Would a try {...} catch {...} statement be good practice?
I assume that you want to check the method doSomething(String, Object).
You might try this:
boolean methodExists = false;
try {
obj.doSomething("", null);
methodExists = true;
} catch (NoSuchMethodError e) {
// ignore
}
This will not work, since the method will be resolved at compile-time.
You really need to use reflection for it. And if you have access to the source code of the method you want to call, it's even better to create an interface with the method you want to call.
[Update] The additional information is: There is an interface that may exist in two versions, an old one (without the wanted method) and a new one (with the wanted method). Based on that, I suggest the following:
package so7058621;
import java.lang.reflect.Method;
public class NetherHelper {
private static final Method getAllowedNether;
static {
Method m = null;
try {
m = World.class.getMethod("getAllowedNether");
} catch (Exception e) {
// doesn't matter
}
getAllowedNether = m;
}
/* Call this method instead from your code. */
public static boolean getAllowedNether(World world) {
if (getAllowedNether != null) {
try {
return ((Boolean) getAllowedNether.invoke(world)).booleanValue();
} catch (Exception e) {
// doesn't matter
}
}
return false;
}
interface World {
//boolean getAllowedNether();
}
public static void main(String[] args) {
System.out.println(getAllowedNether(new World() {
public boolean getAllowedNether() {
return true;
}
}));
}
}
This code tests whether the method getAllowedNether exists in the interface, so it doesn't matter whether the actual objects have the method or not.
If the method getAllowedNether must be called very often and you run into performance problems because of that, I will have to think of a more advanced answer. This one should be fine for now.
Reflection API throws NoSuchMethodException when using Class.getMethod(...) functions.
Otherwise Oracle has a nice tutorial about reflection http://download.oracle.com/javase/tutorial/reflect/index.html
In java this is called reflection. The API allows you to discover methods and call them at runtime. Here is a pointer to the docs. It's pretty verbose syntax but it'll get the job done:
http://java.sun.com/developer/technicalArticles/ALT/Reflection/
I would use a separate method to handle the exception and have a null check to check if method exists
Ex : if (null != getDeclaredMethod(obj, "getId", null)) do your stuff...
private Method getDeclaredMethod(Object obj, String name, Class<?>... parameterTypes) {
// TODO Auto-generated method stub
try {
return obj.getClass().getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
If you're using Spring in your project you may check ReflectionUtil.findMethod(..). It returns null if method does not exist or does not match your requirements. Documentation.
Roland Illig is correct, but wanted to add in an example of how to check if a method exists that requires a parameter using Class.getMethod. Can also use Class.getDeclaredMethod if you are trying to access a private method.
class World {
public void star(String str) {}
private void mars(String str) {}
}
try {
World.class.getMethod("star", String.class);
World.class.getDeclaredMethod("mars", String.class);
} catch (Exception e) {}
Other solution:
public static <O> boolean existsMethod(final String methodName, final O o) {
return Stream.of(o.getClass().getMethods()).map(Method::getName).anyMatch(methodName::equals);
}
Related
I know there is, like, over 5 questions that ask this but mine is different. I am trying to get all classes in a package and run the tick function. Here is what one of my classes look like:
package com.stupidrepo.mydirectory.yayay;
public class test {
public void tick(MinecraftClient client) {
System.out.println(client.player.getName());
}
}
Here is how I am attempting to call this function:
ScanResult scanResult = new ClassGraph().acceptPackages("com.stupidrepo.mydirectory.yayay").enableClassInfo().scan();
private void doIt(MinecraftClient client) {
scanResult.getAllClasses().forEach((classInfo -> {
// System.out.println(classInfo.getName());
try {
classInfo.loadClass().getMethod("tick", MinecraftClient.class).invoke(null, client);
} catch (Exception e) {
e.printStackTrace();
}
}));
}
When I call the doIt function, it keeps giving me the java.lang.NoSuchMethodException error. When I print classInfo.getMethods();, it shows me [public void com.stupidrepo.mydirectory.yayay.test.tick(net.minecraft.client.MinecraftClient)].
So the method is there but java says it isn't. Please help! (By the way the code is for a Fabric MC mod)
The method tick is not static. But, when you are invoking method, you are not giving instance (but null), so it try to run the method as static. Such as It's not static, it failed.
To fix it, you can:
Set your method as static, for example:
package com.stupidrepo.mydirectory.yayay;
public class test {
public static void tick(MinecraftClient client) {
System.out.println(client.player.getName());
}
}
Create a new instance like that:
try {
Class<?> clzz = classInfo.loadClass(); // get class
Object obj = clzz.getConstructor().newInstance(); // create instance
clzz.getMethod("tick", MinecraftClient.class).invoke(obj, client); // get and call method
} catch (Exception e) {
e.printStackTrace();
}
To sum up my project I'm trying to make an event processor that runs methods from a given list of methods. In order to invoke these methods I need to pass in the newInstance of the method. The method is correctly run, however, right after the whole program crashes with a "ConcurrentModificationException".
#EventHandler
private Listener<EventKeyInput> eventKeyInput = new Listener<>(event ->
{
for(Method m : event.getMethods())
{
try {
m.invoke(m.getDeclaringClass().newInstance(), event);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
One of the methods I wish to call
#EventAnnotation()
public void eventKeyInputeTest(EventKeyInput event)
{
System.out.println("EventKeyInput test!");
}
Please let me know if I need to provide anymore code. Thank you for any help!
Edit: Added the class where I change the method
Is there any other way to go about this?
for(Method m : listenable.getClass().getMethods())
{
if(m.isAnnotationPresent(EventAnnotation.class))
{
Parameter[] params = m.getParameters();
if(params.length != 1)
{
System.out.println("You need 1 event paramter!");
}
Class<?> eventType= params[0].getType();
try {
Object methods = eventType.getMethod("getMethods").invoke(eventType.newInstance(), null);
Method add = List.class.getDeclaredMethod("add", Object.class);
add.invoke(methods, m);
eventType.getMethod("setMethods", ArrayList.class).invoke(eventType.newInstance(), methods);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
how to get method return value isFailed along with exception details if method is failed
class sample
{
booelan isFailed=false;
boolean m1()
{
try{
logic of method
}
catch(Exception e)
{
String cause=e.getMessage();
isFailed=true;
}
return isFailed;
}
}
If the calling method needs to know about the Exception, just let it go through.
m1 doesn't have to return a boolean, it either worked or threw an Exception, so the calling method will know whether it is a success or not.
In this example, the calling method (m1Caller) is in the same class for simplicity .
class sample {
boolean isFailed = false;
void m1() throws Exception {
// logic of method
}
void m1Caller() {
try {
m1();
} catch (Exception e) {
// do whatever you want with the Exception's message
System.out.println(e.getMessage());
isFailed = true;
}
}
}
May be it could be silly,but I want to clear my the technical understanding of this code:
import netscape.*;//ldap jar
public class A {
public void method() {
...
try {
//code is written here.
LDAPSearchResults lsr = ldi.search(LDAPConnectionInfo.MY_SEARCHBASE,LDAPConnectionInfo.MY_SCOPE,LDAPConnectionInfo.MY_FILTER,null,false);
while(lsr.hasMoreElements()){
LDAPEntry findEntry = (LDAPEntry)lsr.nextElement();
} catch(...) {
}
}
}
Now I call another class
public class B {
A a = new A();
//here I want to use attributeName
}
How could I access A class's member(in try block) in B class.
Any way to handle try block code for reuse in another class.
How could I handle all those exception in another class.
Any modification should I need...
Calling method of Object type.
public class C{
private String attributeName;
public String getAttributeName() {
return attributeName;
}
public Object method(){
attributeName=lAttribute.getName();
}
}
How could print this Object type method into String(in a jsp page)... any inputs
You'll need a member in class A and a getter:
public class A {
private String attributeName;
public String getAttributeName() {
return attributeName;
}
public void method(){
...
try {
//code is written here.
attributeName = lAttribute.getName();
}
catch() {
}
}
}
Then:
public class B {
A a = new A();
// somewhere
String str = a.getAttributeName();
}
There's no way to access a method's private variables like you did in the original example, as they only exist on the stack during the method call.
Edit: I noticed another question:
How could I handle all those exception in another class.
I assume you want to call your method somewhere else and catch the exceptions there. In that case you can use the throws keyword to communicate that your method will pass exceptions to the caller:
public class A {
public void method() throws IOException {
//code is written here.
String attributeName = lAttribute.getName();
}
public void anotherMethod() {
try {
method();
} catch(IOException ex) {
...
}
}
}
then if some other piece of code calls method it will be forced to either handle or further propagate the exception.
How could I handle all those exception in another class.
In your calling class you can catch Throwable (which will catch all exceptions and errors)
try {
....
}
catch (Throwable t) {
//do something with the throwable.
}
if you do not want to catch Errors (Ive only done this when messing around with ImageIO and had memory problems) in Java then catch Exception instead
Any way to handle try block code for reuse in another class
here you could create a method in another class and then call it within your try /catch block
public class XYX {
public void methodForTry() throws Exception {
//do something
}
}
try {
new XYZ().methodForTry();
}
catch (Exception e){
}
You may or may not want to create new XYZ here. It depends what state this object may or may not hold.
As to the last questions I think Tudor's answer covers this
Your question may be about extracting the code template
try { ... do stuff ... }
catch (MyFirstException e) { ...handle ... }
catch (MySecondException e) { ...handle ... }
... more catch ...
Where you only want to change the ... do stuff ... part. In that case you'd need closures, which are coming with Java 8, and today you'd need something quite cumbersome, of this sort:
public static void tryCatch(RunnableExc r) {
try { r.run(); }
catch (MyFirstException e) { ...handle ... }
catch (MySecondException e) { ...handle ... }
... more catch ...
}
where RunnableExc would be an
interface RunnableExc { void run() throws Exception; }
and you'd use it this way:
tryCatch(new RunnableExc() { public void run() throws Exception {
... do stuff ...
}});
why not return it?
public String method() {
String attributeName
try {
//code is written here.
attributeName = lAttribute.getName();
} catch(...) {
}
return attributeName;
}
public class B {
A a = new A();
String attributeName = a.method();
}
I need to code a method, something like :
MyClassObject convert(Class MyClass , String value)
The convert method's job is to convert the String into an object of MyClass, where MyClass can be anything (except a primitive) - Integer, Boolean, Character, Date... the possibilities are huge here - and that's the reason I gave up my stupid if-else block to handle all the cases individually.
I could see something related to this for C# (don't know if it works) , don't know if we have a Java equivalent for this or this
I understand not everything can be converted from a string, I am ready to handle exceptions for non-parseable items.
I don't know if this is possible or not. If not, please help me with a proper design pattern for my code.
Thanks !
Your best bet is probably the ServiceLoader mechanism. This allows you to define a pair of interfaces, e.g.:
interface StringConverterProvider{
StringConverter<T> getConverterFor(Class<T> clazz);
}
interface StringConverter<T>{
T convert(String s);
}
... and then locate all the implementations of these interfaces available at runtime, like so:
ServiceLoader<StringConverterProvider> converterProviderLoader
= ServiceLoader.load(StringConverterProvider.class);
T convert(String s, Class<T> t){
for(StringConverterProvider scProv : converterProviderLoader){
StringConverter<T> converter = scProv.getConverterFor(t);
if (converter != null)
return converter.convert(s);
}
return null;
}
You make your implementation of the interfaces available to ServiceLoader by listing them in a special file in the META-INF directory in your jar file; see the javadoc for details.
Using reflection and hoping that all the wrapper objects for primitives contains a constructor with a string argument for value, you may be able to achieve this like the following
// A sample test with main
public static void main(String[] args) {
Object obj = create(Integer.class, "54896");
Integer val = (Integer) obj;
System.out.println(val);
}
// Method to create the desired object with the given value
private static Object create(Class myClass, String value) {
Object obj = null;
try {
Constructor constructor = myClass.getConstructor(new Class[]{String.class});
obj=constructor.newInstance(value);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}