Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: How do I override a method of a class dynamically (class is eventually NOT in classpath)?

How do I call a method of a class dynamically + conditionally?
(Class is eventually not in classpath)

Let's say, I need the class NimbusLookAndFeel, but on some systems it's not available (i.e. OpenJDK-6).

So I must be able to:

  • Get to know it that class is available (at runtime),
  • If it's not the case, skip the whole thing.
  • How do I manage to override a method of a dynamically-loaded class
    (thus creating an anonymous inner sub-class of it)?

Code example

public static void setNimbusUI(final IMethod<UIDefaults> method)
    throws UnsupportedLookAndFeelException {

  // NimbusLookAndFeel may be now available
  UIManager.setLookAndFeel(new NimbusLookAndFeel() {

    @Override
    public UIDefaults getDefaults() {
      UIDefaults ret = super.getDefaults();
      method.perform(ret);
      return ret;
    }

  });
}

EDIT:
Now I edited my code, as it was suggested, to intercept NoClassDefFoundError using try-catch. It fails. I don't know, if it's OpenJDK's fault. I get InvocationTargetException, caused by NoClassDefFoundError. Funny, that I can't catch InvocationTargetException: It's thrown anyway.

EDIT2::
Cause found: I was wrapping SwingUtilities.invokeAndWait(...) around the tested method, and that very invokeAndWait call throws NoClassDefFoundError when loading Nimbus fails.

EDIT3::
Can anyone please clarify where NoClassDefFoundError can occur at all? Because it seems that it's always the calling method, not the actual method which uses the non-existing class.

like image 218
java.is.for.desktop Avatar asked Aug 07 '10 19:08

java.is.for.desktop


People also ask

Can I override method without extending class Java?

You can do the following: A anA = new A() { public void method1() { ... } }; This is the same as: private static class myA extends A { public void method1() { ... } }

How do you override a class method?

When overriding a method, you might want to use the @Override annotation that instructs the compiler that you intend to override a method in the superclass. If, for some reason, the compiler detects that the method does not exist in one of the superclasses, then it will generate an error.

Can we override a method without inheritance?

If a method cannot be inherited, then it cannot be overridden. A subclass within the same package as the instance's superclass can override any superclass method that is not declared private or final. A subclass in a different package can only override the non-final methods declared public or protected.


2 Answers

Get to know it that class is available (at runtime)
Put the usage in a try block ...

If it's not the case, skip the whole thing
... and leave the catch block empty (code smell?!).

How do I manage to override a method of a dynamically-loaded class
Just do it and make sure the compile-time dependency is satisfied. You are mixing things up here. Overriding takes place at compile time while class loading is a runtime thing.

For completeness, every class you write is dynamically loaded by the runtime environment when it is required.

So your code may look like:

public static void setNimbusUI(final IMethod<UIDefaults> method)
    throws UnsupportedLookAndFeelException {

    try {
        // NimbusLookAndFeel may be now available
        UIManager.setLookAndFeel(new NimbusLookAndFeel() {

            @Override
            public UIDefaults getDefaults() {
                final UIDefaults defaults = super.getDefaults();
                method.perform(defaults);
                return defaults;
            }

        });
   } catch (NoClassDefFoundError e) {
       throw new UnsupportedLookAndFeelException(e);
   }
}
like image 107
whiskeysierra Avatar answered Oct 13 '22 18:10

whiskeysierra


Use BCEL to generate your dynamic subclass on the fly.

http://jakarta.apache.org/bcel/manual.html

like image 30
Kirk Woll Avatar answered Oct 13 '22 20:10

Kirk Woll