FULL PRODUCT VERSION :
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux 3.13.0-24-generic #47-Ubuntu SMP Fri May 2 23:30:00 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
Class.getDeclaredMethods() returns too many methods when dealing with Typed interfaces.
On a class that implements a typed interface (but is itself not typed), getDeclaredMethods() returns two of the implemented method:
- one for the erasured signature
- one for the actual declared signature.
On a class that extends the above class, getDeclaredMethods() returns one phantom method from the interface.
Both situations do not occur IF the interface is not typed (which further tells me this is a bug).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Declare a typed interface
public interface Bar<T> {
void bar(T t);
}
2. Have a class that declares this method, for a specified type, while not implementing the interface
public class Foo {
public void bar(String s) {}
}
3a. Implement the class for a specific Type
public class ImplementsBar implements Bar<String> {
public void bar(String s) {}
}
3b. Extend the class (Foo), and implement the Typed interface with the specified type. No methods are declared in this class, as the method from the super class satisfies the interface.
public class ExtendsFoo extends Foo implements Bar<String> {}
4. Call getDeclaredMethods()
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
For situation 3a, there is one method declared in the class: public void bar(String s). Only that method should be returned.
For situation 3b, there are no declared methods in the class. I expect no methods to be returned.
ACTUAL -
For situation 3a, I see two methods: public void bar(String) & public void bar(Object)
For situation 3b, I see one method: public void bar(Object)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.lang.reflect.Method;
import java.util.Arrays;
public class DeclaredMethodTest {
interface Bar<T> {
public void bar(T t);
}
class Foo {
public void bar(String s) {}
}
class ImplementsBar implements Bar<String> {
public void bar(String s) {}
}
class ExtendsFoo extends Foo implements Bar<String> {}
public static void main(String... args) {
Arrays.asList(Foo.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("Foo:" + m.toGenericString()));
Arrays.asList(ExtendsFoo.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("ExtendsFoo:" + m.toGenericString()));
Arrays.asList(ImplementsBar.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("ImplmentsBar:" + m.toGenericString()));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
This is possibly the wrong way to setup these classes, and is caused by trying to retrofit existing validators into Spring's validation framework.
In 3a, if ImplementsBar is itself typed, it only returns the Typed method.
In 3b, if Foo is changed to a generic class, and ExtendsFoo specifies the type, getDeclaredMethods returns no methods (as expected).
I accept that this is the right way to setup these classes, but we don't always have control of all of the classes.However, getDeclaredMethods() should return ONLY the methods declared in the class.
import java.lang.reflect.Method;
import java.util.Arrays;
public class DeclaredMethodTest {
interface Bar<T> {
void bar(T t);
}
class Foo<T> {
public void bar(T s) {}
}
class ImplementsBar<T> implements Bar<T> {
public void bar(T s) {}
}
class ExtendsFoo extends Foo<String> implements Bar<String> {}
public static void main(String... args) {
Arrays.asList(Foo.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("Foo:" + m.toGenericString()));
Arrays.asList(ExtendsFoo.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("ExtendsFoo:" + m.toGenericString()));
Arrays.asList(ImplementsBar.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("ImplmentsBar:" + m.toGenericString()));
}
}
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux 3.13.0-24-generic #47-Ubuntu SMP Fri May 2 23:30:00 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
Class.getDeclaredMethods() returns too many methods when dealing with Typed interfaces.
On a class that implements a typed interface (but is itself not typed), getDeclaredMethods() returns two of the implemented method:
- one for the erasured signature
- one for the actual declared signature.
On a class that extends the above class, getDeclaredMethods() returns one phantom method from the interface.
Both situations do not occur IF the interface is not typed (which further tells me this is a bug).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Declare a typed interface
public interface Bar<T> {
void bar(T t);
}
2. Have a class that declares this method, for a specified type, while not implementing the interface
public class Foo {
public void bar(String s) {}
}
3a. Implement the class for a specific Type
public class ImplementsBar implements Bar<String> {
public void bar(String s) {}
}
3b. Extend the class (Foo), and implement the Typed interface with the specified type. No methods are declared in this class, as the method from the super class satisfies the interface.
public class ExtendsFoo extends Foo implements Bar<String> {}
4. Call getDeclaredMethods()
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
For situation 3a, there is one method declared in the class: public void bar(String s). Only that method should be returned.
For situation 3b, there are no declared methods in the class. I expect no methods to be returned.
ACTUAL -
For situation 3a, I see two methods: public void bar(String) & public void bar(Object)
For situation 3b, I see one method: public void bar(Object)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.lang.reflect.Method;
import java.util.Arrays;
public class DeclaredMethodTest {
interface Bar<T> {
public void bar(T t);
}
class Foo {
public void bar(String s) {}
}
class ImplementsBar implements Bar<String> {
public void bar(String s) {}
}
class ExtendsFoo extends Foo implements Bar<String> {}
public static void main(String... args) {
Arrays.asList(Foo.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("Foo:" + m.toGenericString()));
Arrays.asList(ExtendsFoo.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("ExtendsFoo:" + m.toGenericString()));
Arrays.asList(ImplementsBar.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("ImplmentsBar:" + m.toGenericString()));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
This is possibly the wrong way to setup these classes, and is caused by trying to retrofit existing validators into Spring's validation framework.
In 3a, if ImplementsBar is itself typed, it only returns the Typed method.
In 3b, if Foo is changed to a generic class, and ExtendsFoo specifies the type, getDeclaredMethods returns no methods (as expected).
I accept that this is the right way to setup these classes, but we don't always have control of all of the classes.However, getDeclaredMethods() should return ONLY the methods declared in the class.
import java.lang.reflect.Method;
import java.util.Arrays;
public class DeclaredMethodTest {
interface Bar<T> {
void bar(T t);
}
class Foo<T> {
public void bar(T s) {}
}
class ImplementsBar<T> implements Bar<T> {
public void bar(T s) {}
}
class ExtendsFoo extends Foo<String> implements Bar<String> {}
public static void main(String... args) {
Arrays.asList(Foo.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("Foo:" + m.toGenericString()));
Arrays.asList(ExtendsFoo.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("ExtendsFoo:" + m.toGenericString()));
Arrays.asList(ImplementsBar.class.getDeclaredMethods()).stream().forEach((Method m) -> System.out.println("ImplmentsBar:" + m.toGenericString()));
}
}