Can you get the subclass of a Method that was inherited? - java

Take a look at this code:
public class Main {
public class A {
public final void method() {}
}
public class B extends A {}
public static main() {
try {
Method method = B.class.getMethod("method");
//Returns the name of Main$A, but I want Main$B
System.out.println(method.getDeclaringClass().getName());
} catch (NoSuchMethodException e) {}
}
}
I'm trying to get the class out of an inherited method that I previously have taken from a subclass. The reasoning for this is in my application, I store all methods with a specified annotation by object into a Set<Method> and store the object itself in a Map<Class<?>, Object> which is to easily invoke the method later.
I understand that it would make sense for method.getDeclaringClass() to return Main$A, since that's where it was declared, not Main$B, but I was just wondering if there was an alternative to solve my problem.

You're trying to reindex the class methods in a way that is incompatible with the java standards. I don't think there is a workaround for this; your code should reflect the way things are structured; i.e.
populate your map with the class returned by getDeclaringClass().

Related

How pass methods as parameters in Java using method reference notation (Class::method)?

I want to create method in a Utils class that accepts two parameters, the first is the domain class, and the second is a method from the domain class (passed as reference). This Utils' class has a method that will create an instance of the class and execute the method in the scope of the domain class instance.
For example, the domain class:
public class DomainClass {
public void dummyMethod() {}
}
The Utils class:
public class Utils {
public static void execute(Class<?> clazz, Runnable referenceMethod) {
Object objInstance = clazz.getConstructor().newInstance();
// execute the 'referenceMethod' on the scope of 'objInstance'
}
}
The call I want is something like: Utils.execute(DomainClass.class, DomainClass::dummyMethod). However, this scenario has some problems:
How can I pass this parameters for the Utilsclass (now I'm having some compilation problems)?
How can I call the 'referenceMethod' with the scope of 'objInstance'?
DomainClass::dummyMethod is a reference to an instance method, and you need to provide an object instance to run it. This means it cannot be a Runnable, but it can be a Consumer for example.
Also, it will help to make the execute method generic:
public static <T> void execute(Class<T> clazz, Consumer<T> referenceMethod) {
try {
T objInstance = clazz.getConstructor().newInstance();
referenceMethod.accept(objInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
Now you can call execute like this:
Utils.execute(DomainClass.class, DomainClass::dummyMethod);

How to call Enum individual methods?

I have an enum that might look like the one below. My goal is to have an enum with some common methods (I enforced this by adding an abstract method) and some "enum value individual" methods.
The following code compiles:
public enum MyEnum {
VALUE {
#Override
public void syso() {
System.out.println("VALUE syso");
}
},
SPECIAL_VALUE {
#Override
public void syso() {
System.out.println("SPECIAL_VALUE syso");
}
public void sayHello() {
System.out.println("Hello");
}
};
public abstract void syso();
public static void main(String... args) {
MyEnum.VALUE.syso();
MyEnum.SPECIAL_VALUE.syso();
}
}
Running this results in the following being printed:
VALUE syso
SPECIAL_VALUE syso
However trying to call sayHello(), which I defined in SPECIAL_VALUE, does not work.
Adding the following to the main method, does not compile anymore:
public static void main(String... args) {
MyEnum.SPECIAL_VALUE.sayHello(); // does not work
}
Why is that? It seems perfectly fine to me, but the method cannot be found. Is there any way to invoke this method? Maybe via reflection?
I would like to avoid making this method abstract as well, because it does not make sense for any other enum values. I also cannot extend this enum and add this special method, while inheriting the common ones. I would also like to avoid adding some kind of singleton class to "simulate" this.
Is it anyhow possible to run this? If not, what would be my best alternative?
Why is that?
The reason is given in the JLS:
8.9.1. Enum Constants
...
Instance methods declared in enum class bodies may be invoked outside the enclosing enum type only if they override accessible methods in the enclosing enum type (ยง8.4.8).
Is there any way to invoke this method? Maybe via reflection?
Given the above constraint, reflection is the only alternative if you do not want to expose the method in the enclosing enum class. Each enum constant is created as an inner class, like MyEnum$1 and MyEnum$2 in your example. Thus, you can retrieve the Class through the constant's getClass() method and then call your method through reflection (exception handling omitted):
...
Class c = MyEnum.SPECIAL_VALUE.getClass();
Method m = c.getMethod("sayHello");
m.invoke(MyEnum.SPECIAL_VALUE);
...
I would most likely try to avoid reflection and expose the method in the enum class, and let it throw an UnsupportedOperationException:
...
public void sayHello() {
throw new UnsupportedOperationException();
}
...
This at least catches unintended calls during runtime - it still does not allow the compiler to catch them during compile time, but neither does the reflection approach.
Because SPECIAL_VALUE is an instance of enum and enum has only method syso().you are calling
Here is the same thing with classes:
interface Foo {
Foo inst1 = new Foo() {
#Override
public void doFoo() {
}
public void doAnonymous() {
}
};
void doFoo();
}
You cannot call method doAnonymous() like Foo.inst1.doAnonymous() and you are able to access the doAnonymous only via reflection

Java method reference

I've some class with these methods:
public class TestClass
{
public void method1()
{
// this method will be used for consuming MyClass1
}
public void method2()
{
// this method will be used for consuming MyClass2
}
}
and classes:
public class MyClass1
{
}
public class MyClass2
{
}
and I want HashMap<Class<?>, "question"> where I would store (key: class, value: method) pairs like this ( class "type" is associated with method )
hashmp.add(Myclass1.class, "question");
and I want to know how to add method references to HashMap (replace "question").
p.s. I've come from C# where I simply write Dictionary<Type, Action> :)
Now that Java 8 is out I thought I'd update this question with how to do this in Java 8.
package com.sandbox;
import java.util.HashMap;
import java.util.Map;
public class Sandbox {
public static void main(String[] args) {
Map<Class, Runnable> dict = new HashMap<>();
MyClass1 myClass1 = new MyClass1();
dict.put(MyClass1.class, myClass1::sideEffects);
MyClass2 myClass2 = new MyClass2();
dict.put(MyClass2.class, myClass2::sideEffects);
for (Map.Entry<Class, Runnable> classRunnableEntry : dict.entrySet()) {
System.out.println("Running a method from " + classRunnableEntry.getKey().getName());
classRunnableEntry.getValue().run();
}
}
public static class MyClass1 {
public void sideEffects() {
System.out.println("MyClass1");
}
}
public static class MyClass2 {
public void sideEffects() {
System.out.println("MyClass2");
}
}
}
This is feature which is likely to be Java 8. For now the simplest way to do this is to use reflection.
public class TestClass {
public void method(MyClass1 o) {
// this method will be used for consuming MyClass1
}
public void method(MyClass2 o) {
// this method will be used for consuming MyClass2
}
}
and call it using
Method m = TestClass.class.getMethod("method", type);
Method method = TestClass.class.getMethod("method name", type)
Use interfaces instead of function pointers. So define an interface which defines the function you want to call and then call the interface as in example above. To implement the interface you can use anonymous inner class.
void DoSomething(IQuestion param) {
// ...
param.question();
}
You mention in the code comment that each method consumes an object of a certain type. Since this is a common operation, Java already provides you with a functional interface called Consumer that acts as a way to take an object of a certain type as input and do some action on it (two words so far that you already mentioned in the question: "consume" and "action").
The map can therefore hold entries where the key is a class such as MyClass1 and MyClass2, and the value is a consumer of objects of that class:
Map<Class<T>, Consumer<T>> consumersMap = new HashMap<>();
Since a Consumer is a functional interface, i.e. an interface with only one abstract method, it can be defined using a lambda expression:
Consumer<T> consumer = t -> testClass.methodForTypeT(t);
where testClass is an instance of TestClass.
Since this lambda does nothing but call an existing method methodForTypeT, you can use a method reference directly:
Consumer<T> consumer = testClass::methodForTypeT;
Then, if you change the signatures of the methods of TestClass to be method1(MyClass1 obj) and method2(MyClass2 obj), you would be able to add these method references to the map:
consumersMap.put(MyClass1.class, testClass::method1);
consumersMap.put(MyClass2.class, testClass::method2);
While you can store java.lang.reflect.Method objects in your map, I would advise against this: you still need to pass the object that is used as the this reference upon invocation, and using raw strings for method names may pose problems in refactoring.
The cannonical way of doing this is to extract an interface (or use an existing one) and use anonymous classes for storing:
map.add(MyClass1.class, new Runnable() {
public void run() {
MyClass1.staticMethod();
}
});
I must admit that this is much more verbose than the C#-variant, but it is Java's common practice - e.g. when doing event handling with Listeners. However, other languages that build upon the JVM usually have shorthand notations for such handlers. By using the interface-approach, your code is compatible with Groovy, Jython, or JRuby and it is still typesafe.
To answer your direct question regarding using a Map, your proposed classes would be:
interface Question {} // marker interface, not needed but illustrative
public class MyClass1 implements Question {}
public class MyClass2 implements Question {}
public class TestClass {
public void method1(MyClass1 obj) {
System.out.println("You called the method for MyClass1!");
}
public void method2(MyClass2 obj) {
System.out.println("You called the method for MyClass2!");
}
}
Then your Map would be:
Map<Class<? extends Question>, Consumer<Question>> map = new HashMap<>();
and populated like this:
TestClass tester = new TestClass();
map.put(MyClass1.class, o -> tester.method1((MyClass1)o)); // cast needed - see below
map.put(MyClass2.class, o -> tester.method2((MyClass2)o));
and used like this:
Question question = new MyClass1();
map.get(question.getClass()).accept(question); // calls method1
The above works OK, but the problem is that there's no way to connect the type of the key of the map with the type of its value, ie you can't use generics to properly type the value of the consumer and so use a method reference:
map.put(MyClass1.class, tester::method1); // compile error
that's why you need to cast the object in the lambda to bind to the correct method.
There's also another problem. If someone creates a new Question class, you don't know until runtime that there isn't an entry in the Map for that class, and you have to write code like if (!map.containsKey(question.getClass())) { // explode } to handle that eventuality.
But there is an alternative...
There is another pattern that does give you compile time safety, and means you don't need to write any code to handle "missing entries". The pattern is called Double Dispatch (which is part of the Visitor pattern).
It looks like this:
interface Tester {
void consume(MyClass1 obj);
void consume(MyClass2 obj);
}
interface Question {
void accept(Tester tester);
}
public class TestClass implements Tester {
public void consume(MyClass1 obj) {
System.out.println("You called the method for MyClass1!");
}
public void consume(MyClass2 obj) {
System.out.println("You called the method for MyClass2!");
}
}
public class MyClass1 implements Question {
// other fields and methods
public void accept(Tester tester) {
tester.consume(this);
}
}
public class MyClass2 implements Question {
// other fields and methods
public void accept(Tester tester) {
tester.consume(this);
}
}
And to use it:
Tester tester = new TestClass();
Question question = new MyClass1();
question.accept(tester);
or for many questions:
List<Question> questions = Arrays.asList(new MyClass1(), new MyClass2());
questions.forEach(q -> q.accept(tester));
This pattern works by putting a callback into the target class, which can bind to the correct method for handling that class for the this object.
The benefit of this pattern is if another Question class is created, it is required to implement the accept(Tester) method, so the Question implementer will not forget to implement the callback to the Tester, and automatically checks that Testers can handle the new implementation, eg
public class MyClass3 implements Question {
public void accept(Tester tester) { // Questions must implement this method
tester.consume(this); // compile error if Tester can't handle MyClass3 objects
}
}
Also note how the two classes don't reference each other - they only reference the interface, so there's total decoupling between Tester and Question implementations (which makes unit testing/mocking easier too).
Have you tried Method object? refer:
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/reflect/Method.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getMethod%28java.lang.String,%20java.lang.Class...%29
Your question
Given your classes with some methods:
public class MyClass1 {
public void boo() {
System.err.println("Boo!");
}
}
and
public class MyClass2 {
public void yay(final String param) {
System.err.println("Yay, "+param);
}
}
Then you can get the methods via reflection:
Method method=MyClass1.class.getMethod("boo")
When calling a method, you need to pass a class instance:
final MyClass1 instance1=new MyClass1();
method.invoke(instance1);
To put it together:
public class Main {
public static void main(final String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
final Map<Class<?>,Method> methods=new HashMap<Class<?>,Method>();
methods.put(MyClass1.class,MyClass1.class.getMethod("boo"));
methods.put(MyClass2.class,MyClass2.class.getMethod("yay",String.class));
final MyClass1 instance1=new MyClass1();
methods.get(MyClass1.class).invoke(instance1);
final MyClass2 instance2=new MyClass2();
methods.get(MyClass2.class).invoke(instance2,"example param");
}
}
Gives:
Boo!
Yay, example param
Watch out for the following gotchas:
hardcoded method name as a string - this is very hard to avoid
it is reflection, so accessing to the metadata of the class in runtime. Prone to a lot of exceptions (not handled in the example)
you need to tell not only the method name, but the parameter types as well to access to one method. This is because method overloading is standard, and this is the only way to pick the right overloaded method.
watch out when calling a method with parameters: there is no compile time parameter type check.
An alternative answer
I guess what you're looking for is a simple listener: i.e. a way to call a method from another class indirectly.
public class MyClass1 implements ActionListener {
#Override
public void actionPerformed(final ActionEvent e) {
System.err.println("Boo!");
}
}
and
public class MyClass2 implements ActionListener {
#Override
public void actionPerformed(final ActionEvent e) {
System.err.println("Yay");
}
}
using as:
public class Main {
public static void main(final String[] args) {
final MyClass1 instance1=new MyClass1();
final MyClass2 instance2=new MyClass2();
final Map<Class<?>,ActionListener> methods=new HashMap<Class<?>,ActionListener>();
methods.put(MyClass1.class,instance1);
methods.put(MyClass2.class,instance2);
methods.get(MyClass1.class).actionPerformed(null);
methods.get(MyClass2.class).actionPerformed(null);
}
}
This is called the listener pattern. I dared to reuse the ActionListener from Java Swing, but in fact you can very easily make your own listeners by declaring an interface with a method. MyClass1, MyClass2 will implement the method, and then you can call it just like a... method.
No reflection, no hardcoded strings, no mess. (The ActionListener allows passing one parameter, which is tuned for GUI apps. In my example I just pass null.)

Instantiate an object from a dynamically generated class

I am currently trying to achieve something like this:
Based on this class, I try to create a new instance of the class Class<? extends AbstractValidator> returned by the method getValidator().
public abstract class AbstractEnumDefinition
extends AbstractRequestFieldDefinition {
private Vector<String> values = new Vector<String>();
public abstract void define(String lang);
protected void addEnumDefinition(String value){
values.add(value);
}
public Vector<String> getValues(){
return values;
}
#Override
public Class<? extends AbstractValidator> getValidator() {
return new AbstractValidator() {
#Override
public boolean isValid(String value) {
return values.contains(value);
}
#Override
public String getDefaultValue() {
return "";
}
}.getClass();
}
}
Say I create this class:
public class LanguageDefinition extends AbstractEnumDefinition {
public LanguageDefinition() {
super();
}
#Override
public void define(String language) {
addEnumDefinition("BEL-fr");
addEnumDefinition("BEL-nl");
addEnumDefinition("BEL-en");
}
}
Later in my code, I call
new LanguageDefinition().getValidator().getConstructor().newInstance()
The class I am trying to instantiate here is not declared anywhere, but "generated dynamically"/"dynamically created" within the AbstractEnumDefinition class.
When trying to do this, I get an java.lang.InstantiationException for
be....servlets.model.extraction.filter.editor.AbstractEnumDefinition$1
I guess this is due to the fact that this Class has to be explicitly created before hand, and not referenced dynamically?
Is there some kind of solution that would allow me to not have to write one class per validator?
Thanks for the help,
Eric
I can only make assumptions since i don't see the code where you are actually using the class, but you should check: http://docs.oracle.com/javase/6/docs/api/java/lang/InstantiationException.html
One thing it mentions is the instantiation can fail is the class is an abstract class (perfectly logical since you can't instantiate abstract classes).
Also, i don't see why you need to return the class and then create and object. Why not just define a Validator Interface and have your method return a Validator object.
That does not work for anonymous classes as far as I know, you have to convert your class to a named inner class:
But even that will not work, properly because you might not have a default constructor. Inner classes get implicit constructor arguments to keep the reference to the enclosing class. Unfortunately Closures do not work so well in static languages.
In summary inner classes that are non-static can not be instantiate outside of an instance of the enclosing class.

Java Reflection/Generic

Given the following three classes how can I use reflection to call the initialize function for the parent class(es) and then the subclass:
public class Test {
public static void main(String[] args) {
ExtendedElement ee = new ExtendedElement();
initialize(ee);
}
public static void initialize(Element element) {
System.out.println(element.getClass());
initialize(element.getClass());
}
public static void initialize(Class clazz) {
System.out.println(clazz.getClass());
}
}
public class Element {
protected String value;
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
}
public class ExtendedElement extends Element {
protected String extendedValue;
public void setExtendedValue(String extendedValue) {
this.extendedValue = extendedValue;
}
public String getExtendedValue() { return extendedValue; }
}
I'm not quite sure on how to paramertize the initialize function in the Test class, as the clazz parameter is a raw type.
What I essentially need is to call initialize up the class hierarchy if what I pass into initialize is of a subclass of Element.
Something like the following:
public void initialize(Class clazz) {
if (Element.class.isInstance(clazz.getClass().getSuperclass()) {
initialize(clazz.getClass().getSuperclass());
}
//Work to call initialize function
}
Edit 1:
Can't I parameterize the above pseudo function differently to retain the type of the object and then call the function I need to?
What I'm trying to do is avoid having to have the same method overridden for each of my classes and allow some inheritance for my Selenium 2 Page Objects. What I need to do is be able to is introspect the superclass(es) of my self and initialize each of my WebElement fields prior to running tests on these fields.
These are being injected with spring, and to further complicate things I am allowing tests to be written using Spring Expression language. I am lazy loading my beans, and using the InitializingBean interface to attempt to initialize my WebElements prior to their usage to avoid NPEs.
I had to wrap the WebElements with a custom object so that I could inject the location strategies using spring (We reuse a lot of pieces, but they have different ids / class names dependent upon where they are used in the application; this was done prior to me getting here and will not be changed at this time despite my arguments for consistency). For example we have a date widget that has different granularities, sometimes we need just a month, sometimes month and year, etc... It'd be nice if I could use an abstract class and break these commonalities down to their least common denominator and extend from there. To do that I need to be able to do the following in my base class:
public abstract class PageObject implements InitializingBean {
...
public void afterPropertiesSet() {
//Pass in concrete impl we are working with - this allows me to initialize properly
initializeWebElements(this.getClass());
}
...
public void initializeWebElements(Class clazz) {
//This does not grab inherited fields, which also need to be initialized
for (Field field : clazz.getDeclaredFields()) {
if (WidgetElement.class == field.getType()) {
Method getWidgetElement = clazz.getDeclaredMethod("get" +
StringUtils.capitalize(field.getName()), new Class [] {});
WidgetElement element =
(WidgetElement) getWidgetElement.invoke(this, new Object [] {});
element.initElement();
}
}
You can't call a method at a specific level. The only thing is you have access to the super keyword inside the class itself.
To make this work, you want to call super.initialize() from within each subclass, then just call it via reflection.
This is not C++, where you can call a specific method at a specific level of the inheritance hierarchy.
I'm not quite sure on how to parameterize the initialize function in the Test class, as the clazz parameter is a raw type.
Nothing in your example requires you to make use of the generic type parameter, so declare it as Class<?>.
I don't understand what your initialize methods are really trying to do, but there are a number of problems:
You seem to have one initialize method that takes an instance (of Element) as an argument, and another that takes a Class object as an argument. That's really apples and oranges stuff ... and you need to explain what you are trying to do.
Your attempt at fleshing out the method contains this:
Element.class.isInstance(clazz.getClass().getSuperclass())
This will never evaluate to true, because it is asking if some Class object is an instance of the Element class. (What is more, clazz.getClass().getSuperclass() is actually going to be the same as java.lang.Object.class. The class of a Class object is java.lang.Class and its superclass is java.lang.Object).
But I can't figure out what it should be, because you don't clearly describe what you are trying to achieve.
Here is my temporary solution, leaving question open to hopefully gather some better answers though for my use case.
public abstract class PageObject implements InitializingBean {
...
public void afterPropertiesSet() {
Class clazz = this.getClass();
do {
initializeElements(clazz);
clazz = clazz.getSuperclass();
} while (clazz != null);
}

Categories

Resources