This is a good discussion but none of the suggestions satisfy the need I'm
looking
for.https://stackoverflow.com/questions/450807/how-do-i-make-the-method-return-type-generic
The example code below shows button0 being added to a VBox. It also shows
button1 being added to the same VBox only instead of being added directly to
the list returned by vbox.getChildren(), that is
vbox.getChildren().add(button1), buttton1 is added via
reflection/introspection. The end goal is the same in both cases. Add a button.
The methodology is different. Regardless, this should be trivial. It's not. Why?
In this example, adding button0 produces no compile time warnings, Attempt-1.
As for the code adding button1, Attempt-3 too produces no compile time warning,
yet when run produces the WARNINGS shown at the bottom of the code. Commenting
out Attempt-3 and uncommenting Attempt-2, produces compile time warnings.
The bottom of the code example shows how to compile and run the example.
As is, this code references no illegal reference code and yet still produces
run time WARNINGS.
Is there a way to access the list returned by getChildren() via reflection so a
widget can be added without producing the run time WARNINGS? It's not the
WARNINGS that I'm concerned about. I'm concerned that when future Java releases
become available this code will fail to work. I would like to find a solution
so that doesn't happen and this code continues to work.
Maps have similar behavior. Try and use reflection to iterate over a Map, a
trivial exercise, and it quickly becomes an impossible task. The internal class
of the Map isn't public making it impossible to iterate through the list. I'm
assuming that is what we are seeing here as well.
Personally I believe internal classes should never be used. They seem to
produce more problems than they solve. They are a quick, lazy fix that usually
results in painful long term support. Besides, internal classes defeat write
once, run anywhere. If it's internal, it's not being used anywhere else; which
means the code has no useful value elsewhere; obviously false. That implies the
code will be duplicated elsewhere to leverage it's functionality, meaning the
code is now written twice, defeating the montra. Therefore, internal classes
should never be used. In the same spirit, classes should never be private for
the same reason. The nice thing is, convention easily satisfies this
suggestion. Just because you can, doesn't mean you should.
Java has been out for 23 years. Does a solution exist? I would like to see this
example code work for future releases of Java.
Is there a solution? Would you please point me at an example.
Thanks
---------- BEGIN SOURCE ----------
public class ReflectAccessBug extends javafx.application.Application {
public static void main(String[] args) {
launch(args);
}
public void start(javafx.stage.Stage stage) {
javafx.scene.control.Button button0 = new javafx.scene.control.Button();
javafx.scene.control.Button button1 = new javafx.scene.control.Button();
javafx.scene.layout.VBox vbox = new javafx.scene.layout.VBox();
javafx.event.EventHandler<javafx.event.ActionEvent> event = e -> {
javafx.scene.control.Button b =
(javafx.scene.control.Button)e.getSource();
System.err.println(b.getText() + " " + e);
};
button0.setText("button0");
button0.setOnAction(event);
button1.setText("button1");
button1.setOnAction(event);
vbox.getChildren().add(button0);
// Attempt-1
// This works as expected.
//vbox.getChildren().add(button1);
try {
// Now let's try adding button1 using introspection ...
java.lang.reflect.Method m =
vbox.getClass().getMethod("getChildren", new Class[0]);
Object o = m.invoke(vbox, new Object[0]);
/*
// Attempt-2
// This causes the same runtime warning as Attempt-3
// and I don't believe it should.
// Attempt-2 produces a compile time warning.
// Attempt-3 eliminates the compile time warning.
javafx.collections.ObservableList<javafx.scene.Node> l =
(javafx.collections.ObservableList<javafx.scene.Node>)o;
m = l.getClass().getMethod("add", new Class[] { Object.class, });
o = m.invoke(l, new Object[] { button1, });
System.err.println("o="+o);
*/
// Attempt-3
// This results with the same runtime warning as Attempt-2.
// I don't believe it should produce this warning and is the
// point of this exercise.
// Attempt-3 produces *NO* compile time warning as in Attempt-2.
// It's not the compile time warning I'm concerned about. It's the
// runtime warning that is the issue.
// This code references no illegal reference code and yet still
// produces a runtime warning. It references
// "illegal reflective access operations". It's not this code
// that is illegally accessing reflective code. Lower level code
// accesses illegal reflective code on behalf of this code.
m = o.getClass().getMethod("add", new Class[] { Object.class, });
o = m.invoke(o, new Object[] { button1, });
System.err.println("o="+o);
} catch (Exception x) {
x.printStackTrace();
}
javafx.scene.Scene scene0 = new javafx.scene.Scene(vbox);
stage.setScene(scene0);
stage.show();
}
}
/*
# compile:
javac ReflectAccessBug.java
# run:
java ReflectAccessBug
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by ReflectAccessBug (...) to method
com.sun.javafx.collections.VetoableListDecorator.add(java.lang.Object)
WARNING: Please consider reporting this to the maintainers of ReflectAccessBug
WARNING: Use --illegal-access=warn to enable warnings of further illegal
reflective access operations
WARNING: All illegal access operations will be denied in a future release
*/
---------- END SOURCE ----------