I want to test a private method using reflection. In this case isEdible method from Food class.
public class Food {
private Boolean isEdible() {
return true;
}
}
When I'm using getDeclaredMethod without specifying Food class, it ran successfully.
#Test
public void foodTestOne() throws Exception {
Food food = new Food();
Method method = food.getClass().getDeclaredMethod("isEdible");
method.setAccessible(true);
boolean isEdible = (boolean) method.invoke(food);
assertTrue(isEdible);
}
But when I add Food Class on a second parameter I got NoSuchMethodException.
#Test
public void foodTestTwo() throws Exception {
Food food = new Food();
Method method = food.getClass().getDeclaredMethod("isEdible", Food.class);
// execution stop here
}
My questions are:
What should I put in second parameters to make it work? Changing getDeclaredMethod("isEdible", Boolean.class) still throws the same Exception.
It seems pretty basic and intuitive, why is this happening?
getDeclaredMethod needs to match the argument types that the method expects. When a method takes no arguments (such as isEdible()) you can pass null (or an empty Class[]), for example
public class Food {
private Boolean isEdible() {
return true;
}
public static void main(String[] args) {
Food food = new Food();
try {
Class<?>[] methodArgumentTypes = null; // {};
Object[] methodArguments = null; // new Object[0];
Method method = food.getClass().getDeclaredMethod("isEdible",
methodArgumentTypes);
System.out.println(method.invoke(food, methodArguments));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Will actually invoke isEdible() and output true.
Can be done like this, if method has no parameters:
obj.getClass().getDeclaredMethod(methodName, (Class<?>[]) null).invoke(obj);
Read more...
The issue you are having is that in the line
Method method = food.getClass().getDeclaredMethod("isEdible", Food.class);
You specify Food as a parameter of the method; it is not. Instead, you should have
Method method = food.getClass().getDeclaredMethod("isEdible");
isEdible() is declared private, so you will not be able to access it in the current context, even with getDeclaredMethod. To allow for access, you can set it to accessible before invoking the method.
method.setAccessible(true);
method.invoke(food);
Related
So, I have the following classes:
public class MainClass{
public void run(String infoOne, String infoTwo, String infoThree, String infoFour, String infoFive, String infoSix){
SomeClass someClass = new SomeClass();
someClass.runSomeMethod();
someClass.runSomeMethodTwo( infoOne);
someClass.runSomeMethodThree( infoThree, infoOne, infoSix);
someClass.runSomeMethodFour( infoTwo, infoFive);
someClass.runSomeMethodFive(infoThree, infoFive, infoOne, infoSix);
}
}
public class SomeClass{
public boolean runSomeMethod(){
// do something
}
public boolean runSomeMethodTwo(String arg){
// do something
}
public boolean runSomeMethodThree(String argOne, String argTwo, String argThree){
// do something
}
public boolean runSomeMethodFour(String argOne, String argTwo){
// do something
}
public boolean runSomeMethodFive(String argOne, String argTwo, String argThree, String argFour){
// do something
}
}
As you can see it's a bunch of methods taking only Strings as parameters (but a different amount every time). What I want now is to wrap each single method in a try catch block and log some results. To do that I wanted to put a method in between that handles the logging:
log(SomeClass::runSomeMethodFour);
public void log(????? method, String...args){
try{
if(method.execute(args);
System.out.println("Success!");
} else {
System.out.println("Failed to execute!");
}
} catch (Exception e){
e.printStackTrace();
}
}
Is this possible in some way? To pass a dynamic number of arguments to a lambda function? Or could I do something with generics?
There is no need to create a complicated Reflection-based solution. Your problems stem from the unnecessary attempt to separate the method and the parameter arguments, instead of just encapsulating the entire action like
public class MainClass {
public void run(String infoOne, String infoTwo, String infoThree,
String infoFour, String infoFive, String infoSix) {
SomeClass someClass = new SomeClass();
log(() -> someClass.runSomeMethod());
log(() -> someClass.runSomeMethodTwo(infoOne));
log(() -> someClass.runSomeMethodThree(infoThree, infoOne, infoSix));
log(() -> someClass.runSomeMethodFour(infoTwo, infoFive));
log(() -> someClass.runSomeMethodFive(infoThree, infoFive, infoOne, infoSix));
}
public void log(BooleanSupplier method) {
try {
if(method.getAsBoolean()) {
System.out.println("Success!");
} else {
System.out.println("Failed to execute!");
}
} catch (Exception e ){
e.printStackTrace();
}
}
}
For the work of the log method, only the boolean return value is relevant, which matches the functional signature of BooleanSupplier.
JLS described Method Reference Expression:
The compile-time declaration of a method reference is the method to which the expression refers. In special cases, the compile-time declaration does not actually exist, but is a notional method that represents a class instance creation or an array creation. The choice of compile-time declaration depends on a function type targeted by the expression, just as the compile-time declaration of a method invocation depends on the invocation's arguments.
A method reference expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived from T.
the method reference expression must be assign an exactly Function Interface at compile time. and Function Interface is a SAM Interface. so you can't bind a method handler dynamically by method reference expression at runtime.
but you can using reflection or invoke api to achieve it.
let see each method expression refer to a Function Interface in your SomeClass results in refers to different Function Interface type:
SomeClass it = new SomeClass();
BooleanSupplier first1 = it::runSomeMethod;//bound
Predicate<SomeClass> first2 = SomeClass::runSomeMethod;//unbound
Predicate<String> second1 = it::runSomeMethodTwo;//bound
BiPredicate<SomeClass, String> second2 = SomeClass::runSomeMethodTwo;//unbound
...
Hearing about "reflection" as a comment by Oliver Charlesworth I came up with the following solution:
public class Test {
static Test testLogger = new Test(); //This should be another class ofcourse, but it doesn't matter for this example
public static void main(String[] args) throws NoSuchMethodException, SecurityException{
Test test = new Test();
run(test, "something", "hi", "hai", "blaa");
}
public static void run(Object pageObjectModel, String methodName, String...arguments){
Class<String>[] args = new Class[arguments.length];
Arrays.fill(args, String.class);
try {
testLogger.log(pageObjectModel, pageObjectModel.getClass().getMethod(methodName, args), arguments);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
private void log(Object pageObjectModel, Method method, String...arguments) {
try {
if((Boolean)method.invoke(pageObjectModel, (Object[])arguments)){
System.out.println("Success!");
} else {
System.out.println("Fail!");
}
} catch (Exception e){
e.printStackTrace();
}
}
public boolean something(String one, String two, String three){
System.out.println(one+", "+two+", "+three);
return true;
}
}
This seems to be perfect for what I'm trying to achieve. Although I don't really like reflection due to having bad experiences with it (giving problems with obfuscated code) I think it's fine for this project.
Thanks for helping me in the right direction!
I want to save a method in an Enum, but Class.getDeclaredMethod is throwing NoSuchMethodException, so how can I handle it?
My Code:
public enum Card {
OPENPRISON(false, Cards.class.getDeclaredMethod("", Player.class));
private boolean isInstant;
private Method method;
private Card(boolean isInstant, Method method){
this.method = method;
this.isInstant = isInstant;
}
public boolean isInstant() {
return isInstant;
}
public void run(Player p){
}
}
and OPENPRISON is the problem
An immediate technical issue is that you're not providing a method name in your call to getDeclaredMethod():
OPENPRISON(false, Cards.class.getDeclaredMethod("", Player.class));
A larger issue is why you need to use reflection at all.
An enum value is a constant. What can you do with reflection that you could not as easily do with a static method? Or with a method outside the enum?
Well your code throws a checked exception, so you could use a method:
OPENPRISON(false, foo());
private static Method foo() {
try {
return Cards.class.getDeclaredMethod("", Player.class);
} catch (NoSuchMethodException e) {
return null;
}
}
Of course, the question remains if you cannot solve your problem without reflection - most likely it is possible.
Im beginner JAVA developer. Here is a method:
private Method getSomething()
{
for (Method m : getClass().getDeclaredMethods())
{
return m;
}
return notFound;
}
private void notFound()
{
throw new Exception();
}
it doesnt matter what it does - if it finds something, then returns a Method - if not, the notFound() method itself should be returned. So the hot spot is at the return notFound; line: if I use return notFound(); then it returns its value, not the method itself. I want something like a reference/pointer. So getSomething() returns something what can be called, and if the returned method is used wrong, it should trigger that Exception - so its not an option to replace return notFound; with throw new Exception(); !
Or the 2nd option is to create a lambda method....
You need to call
this.getClass().getMethod("notFound")
to get the notFound method of the current/this object's class.
So just do this:
return this.getClass().getMethod("notFound");
More details here:
Class.getMethod
EDIT:
You can retrieve i.e. get and call private methods too via reflection.
Here is an example.
import java.lang.reflect.Method;
public class Test001 {
public static void main(String[] args) throws Exception {
Test002 obj = new Test002();
Method m = obj.getClass().getDeclaredMethod("testMethod", int.class);
m.setAccessible(true);
m.invoke(obj, 10);
m.invoke(obj, 20);
System.out.println(m.getName());
}
}
class Test002 {
private void testMethod(int x){
System.out.println("Hello there: " + x);
}
}
You need to use reflection to achieve this:
http://docs.oracle.com/javase/tutorial/reflect/
e.g. to get all methods of a given class:
Class aClass = ...//obtain class object
Method[] methods = aClass.getMethods();
I keep getting this error message:
06-13 18:53:33.839: W/System.err(19893): java.lang.NoSuchMethodException: showIt
06-13 18:53:33.839: W/System.err(19893): at java.lang.ClassCache.findMethodByName(ClassCache.java:247)
06-13 18:53:33.839: W/System.err(19893): at java.lang.Class.getDeclaredMethod(Class.java:731)
I'm sure my method exists, I try to start from within a asynctask.
This is the method:
public static void showIt(String[] result) {
And this is the code I've tried:
try {
Class<?> p = Class.forName(executeClass);
Object t = p.newInstance();
Method m = p.getDeclaredMethod(executeMethod, p);
m.invoke(t, result);
} catch (Exception e) {
e.printStackTrace();
}
Three problems ...
getDeclaredMethod second argument must be an array of parameters classes of the showIt method.
Because the method is static, it is useless to pass an object to the first argument of invoke method.
Because the invoke method is varargs, result must be wrapped into a Object[] in order to be passed as excepted.
Finally, here is a working code snipet.
String[] result = new String[] { "res" };
Class<?> p = Class.forName(executeClass);
Method m = p.getDeclaredMethod("showIt", result.getClass());
m.invoke(null, new Object[] {result});
Given executeClass = "YourClass" and executeMethod = "showIt", p.getDeclaredMethod(executeMethod, p) is trying to find showIt(YourClass arg), but you have showIt(String[] arg).
Try p.getDeclaredMethod(executeMethod, String[].class).
You got two mistakes here:
you have to pass getDeclaredMethod the type of argument as second parameter, and not the type of your class (p)
since your method is static, you have to pass null as first parameter to invoke, and you don't need to create the t instance.
.
public class Main {
public static void main(String[] args){
try {
Class<?> p = Main.class;
String[] arguments = {"ciao"};
Method m = p.getDeclaredMethod("showIt",String[].class);
m.invoke(null, arguments);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void showIt(String[] result) {
System.out.println(result[0]);
}
}
I want to transfer a variable value of type List (variable name is seznamRacunov) from one class to another.
Class 1
public class UvoziRacun
{
private String potRacuna;
private List<String> seznamRacunov = new ArrayList();
public void setRacun(List<String> seznamRacunov)
{
this.seznamRacunov = seznamRacunov;
}
public List<String> getRacun()
{
return seznamRacunov;
}
public String getPotRacuna()
{
return potRacuna;
}
public void showDailog()
{
try
{
JFileChooser racun = new JFileChooser();
racun.setCurrentDirectory(new File(""));
racun.setFileFilter(new javax.swing.filechooser.FileFilter()
{
public boolean accept(File f)
{
return f.getName().toLowerCase().endsWith(".xml") || f.isDirectory();
}
public String getDescription()
{
return "XML Datoteka";
}
});
//racun.setMultiSelectionEnabled(true);
int r = racun.showOpenDialog(new JFrame());
if (r == JFileChooser.APPROVE_OPTION)
{
potRacuna = racun.getSelectedFile().getPath();
seznamRacunov.add(potRacuna); //value is stored
}
//System.out.print("Racuni: " + seznamRacunov);
}
catch(Exception ex){}
}
}
Class 2
public class PrikaziRacune extends javax.swing.JFrame
{
UvoziRacun rac = new UvoziRacun();
public PrikaziRacune()
{
initComponents();
try
{
System.out.print(rac.getRacun()); // value is null, why?
//jLabel2.setText();
}
catch(Exception ex){}
}
Method seznamRacunov.add(potRacuna); store a value into seznamRacunov in Class 1, but the value of list does not pass in class 2 where I called getter. What is wrong?
Method seznamRacunov.add(potRacuna); store a value into seznamRacunov
in Class 1, but the value of list does not pass in class 2 where I
called getter.
Thats because, you are trying to get() your List without even calling the method - showDailog() which in turn invokes your add() method to populate list.
Make sure, you invoke this method - showDailog() to populate the list, before you actually fetch the List with get method
Or, it would be better, if you add a constructor to your class, which does the task of initializing your List. Then you can create an instance using that constructor and thus you won't have any problem.
PS: - You should always have at least a 0-arg constructor to initialize your fields, rather than letting compiler handle this task for you.
And one more thing, you should never, ever engulp your exception by having an empty catch block. Else there is no point in catching them. Add a printStackTrace() call instead.
public PrikaziRacune() {
initComponents();
try
{
rac.showDailog(); // Will populate the list
System.out.print(rac.getRacun()); // You can get the value here.
//jLabel2.setText();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
Also, check your ArrayList declaration in your first class. You are using generic type List on LHS, and a Raw type ArrayList on the RHS. Its something that you should avoid.
Have Generic type on both the sides: -
private List<String> seznamRacunov = new ArrayList<String>();