jeffrey kutcher
2018-01-12 18:26:35 UTC
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 ----------
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 ----------