Invoke a method by reflection

2

I took a look at this question Has how to pass methods as a parameter? and tried to invoke one method from one class, in another, passing as parameters the screen / class and the method name.

The purpose of doing this is that in my application, I do several routines within a given method, which is triggered by an event (a ActionListener , for example) and every time I need to do something "different" , I have to overwrite the event that triggers this method, put the new routine and sometimes even repeat others.

I believe doing it this way, I could have a greater chance at doing some routines. I could have several different screens with the MyField component that does the same function, and on the screens I want a certain method to be executed together or after the MyField methods, I would do it quietly, passing it as a parameter.

It seems to me to be a coherent idea, but I may be wrong, and in this case, I am open to more efficient and "correct" suggestions.

To better illustrate what I intend, I made a simple example.

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class TesteReflection extends JFrame {

    public static void main(String[] args) {
        Runnable startApp = () -> {
            TesteReflection tr = new TesteReflection();
        };
        SwingUtilities.invokeLater(startApp);
    }

    private MyField myField = new MyField();
    private JButton button = new JButton("Click !");

    public TesteReflection() {
        add(button);
        setSize(300, 200);
        setVisible(true);
        button();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void button() {
        button.addActionListener(e -> {
            metodoA();
        });
    }

    private void metodoA() {
        MyField.actions(myField, TesteReflection.class, "metodoB");
    }

    private void metodoB() {
        System.out.println("Método B");
        //faz alguma coisa ..
    }
}
import java.lang.reflect.Method;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class MyField extends JPanel {

    private JTextField jTextField = new JTextField();

    public MyField() {
        actions();
    }

    private void actions() {
        jTextField.addActionListener(e -> {
            //faz alguma coisa ..
        });
    }

    public static void actions(MyField component, Class tela, String methodName) {
        component.getjTextField().addActionListener(e -> {
            try {
                //Method method = tela.getDeclaredMethod(methodName, new Class[]{});
                Method method = tela.getClass().getDeclaredMethod(methodName, String.class);
                method.setAccessible(true);
                method.invoke(tela);

                System.out.println("Chamei com sucesso o método " + methodName);
            } catch (Exception ev) {
                ev.printStackTrace();
            }
        });
    }

    public JTextField getjTextField() {
        return jTextField;
    }

}
    
asked by anonymous 28.03.2018 / 00:16

1 answer

2

Your reflection fails because metodoB is an instance method and not a static method. So, to invoke it (usually or by reflection), you need the instance.

You even try to solve this using tela.getClass() . However, tela is Class , and therefore the result of this would be Class.class , which is definitely not what you want. Also, specifying String.class as a parameter, you will not find what you wanted, because the method you want is only metodoB() and not metodoB(String) .

The code looks like this:

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class TesteReflection extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new TesteReflection();
        });
    }

    private MyField myField = new MyField();
    private JButton button = new JButton("Click !");

    public TesteReflection() {
        add(button);
        setSize(300, 200);
        setVisible(true);
        button();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void button() {
        button.addActionListener(e -> metodoA());
    }

    private void metodoA() {
        myField.actions(this, TesteReflection.class, "metodoB");
    }

    private void metodoB() {
        System.out.println("Método B");
        //faz alguma coisa ..
    }
}
import java.lang.reflect.Method;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class MyField extends JPanel {

    private JTextField jTextField = new JTextField();

    public MyField() {
    }

    public <E> void actions(E tela, Class<E> classe, String methodName) {
        jTextField.addActionListener(e -> {
            try {
                Method method = classe.getDeclaredMethod(methodName);
                method.setAccessible(true);
                method.invoke(tela);

                System.out.println("Chamei com sucesso o método " + methodName);
            } catch (Exception ev) {
                ev.printStackTrace();
            }
        });
    }
}

However, what you want probably would be better and easier with method references :

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class TesteReflection extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new TesteReflection();
        });
    }

    private MyField myField = new MyField();
    private JButton button = new JButton("Click !");

    public TesteReflection() {
        add(button);
        setSize(300, 200);
        setVisible(true);
        button();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void button() {
        button.addActionListener(e -> metodoA());
    }

    private void metodoA() {
        myField.actions(this::metodoB);
    }

    private void metodoB() {
        System.out.println("Método B");
        //faz alguma coisa ..
    }
}
import javax.swing.JPanel;
import javax.swing.JTextField;

public class MyField extends JPanel {

    private JTextField jTextField = new JTextField();

    public MyField() {
    }

    public void actions(Runnable r) {
        jTextField.addActionListener(e -> r.run());
    }
}
    
28.03.2018 / 00:34