1

I'm using an Eclipse based software which allows to create applications and automatically provides a default user interface. I'm trying to modify this interface (e.g. change buttons icon, foreground color etc...) but unfortunately I cannot modify the source code, so I'm trying to do it via java reflections. I can anyway take vision of the compiled jar files thanks to softwares like JD-GUI, but I'd prefer not to modify and recompile the jars. The problem is that this interface is built through customized classes which extends Swing components and, looking into the jar files, I found some annoying tricks implemented. Follows an example:

final class MyToggleButton extends JToggleButton{
    MyToggleButton (ImageIcon defaultIcon){
        super.setIcon(defaultIcon);
    }
    @Override
    public void setIcon(Icon icon){}
}

With classes built in this way, if I invoke the setIcon() method on an instance of MyToggleButton, it doesn't make effect, since the override method has no code inside (I think). So I cannot change the icon they set by default on the specific button.

Does anyone know a way to overcome this issue? Thanks in advance for any help.

P.S. I'm not a javer but I'm quite familiar with reflections.

Roberto
  • 243
  • 1
  • 5
  • 15

3 Answers3

1

This is not possible. Invoking a superclass method and bypassing the override in the class is only possible through a special bytecode instruction (invokespecial), which can only be used inside the class which overrides the method. There is no way to perform such a call through reflection.

yole
  • 92,896
  • 20
  • 260
  • 197
  • yole, thanks for your response. Just to be sure I got the point, does this mean that, owing to the above mentioned source code, there is no way to change JToggleButton's icon? – Roberto Jan 29 '16 at 17:04
  • The easiest way to change the icon is to unpack the .jar file, change the file containing the icon and repack it again. This is much easier to do than decompiling and recompiling the classes, and much more reliable than any reflection tricks you may come up with. – yole Jan 29 '16 at 17:37
0

You can't invoke the superclass' version of a method. But, through reflection, you could probably execute the same logic. For example, through reflection, you could assign your icon to a field in JToggleButton, and invoke methods that dispatch a property change event to registered listeners, etc.

Essentially, you'd look at the source code for JToggleButton (or where ever the method is defined), and reproduce code in its original setIcon() method using reflection. Not easy, pretty or maintainable, but it will work.

erickson
  • 265,237
  • 58
  • 395
  • 493
  • Thank you very much for your help. Unfortunately this seems a bit complicated for me since I'm not a programmer. Can you please provide me, if it's not to much trouble, an example of the required code using the class I posted above? – Roberto Jan 29 '16 at 17:15
0

As others have mentioned, it is not possible to call a superclass's method through reflection if it has been overridden. If at all possible you should look for another way of solving your issue before doing this, such as yole's suggestion, as this is both difficult to read and maintain (it could easily break unexpectedly if, for example, the setIcon() method implementation changes or the default_icon field changes name).

However, if you absolutely want to and must you can do something like this to "mimic" the method call based on the source for setIcon() here on line 1710.

public static void setButtonIcon(MyToggleButton button, Icon icon) {
      if (button.getIcon() == icon)
            return;

      Icon old = button.getIcon();

      // Use reflection to set the icon field
      try {
            Field f = AbstractButton.class.getDeclaredField("default_icon");
            f.setAccessible(true);
            f.set(button, icon);
      } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
            return;
      }

      button.firePropertyChange(AbstractButton.ICON_CHANGED_PROPERTY, old, icon);
      button.revalidate();
      button.repaint();
}

Reflection reference