RFR: 8313651: Add 'final' keyword to public property methods in controls [v2]

Nir Lisker nlisker at openjdk.org
Sun Aug 20 21:19:33 UTC 2023


On Fri, 18 Aug 2023 22:17:15 GMT, Andy Goryachev <angorya at openjdk.org> wrote:

>> In the Control hierarchy, all property accessor methods must be declared `final`.
>> 
>> Added a test to check for missing `final` keyword and added the said keyword where required.
>
> Andy Goryachev has updated the pull request incrementally with one additional commit since the last revision:
> 
>   review comments

modules/javafx.controls/src/test/java/test/javafx/scene/control/ControlPropertiesTest.java line 84:

> 82: import javafx.scene.control.cell.TextFieldTreeTableCell;
> 83: import org.junit.Assert;
> 84: import org.junit.Test;

These are JUnit 4, we should use 5 for new tests.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ControlPropertiesTest.java line 98:

> 96:  */
> 97: public class ControlPropertiesTest {
> 98:     private static final boolean FAIL_FAST = true;

We use an empty line after the class declaration.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ControlPropertiesTest.java line 103:

> 101:     // https://stackoverflow.com/questions/28678026/how-can-i-get-all-class-files-in-a-specific-package-in-java
> 102:     private Class[] allControlClasses() {
> 103:         return new Class[] {

I was also thinking that these should be generated by the contents of the package. When I looked at javafx.scene.control I saw classes that weren't controls, but were used by them, so they would need to be removed. So it's a question of whitelist vs. blacklist.

In any case, I'm not sure why you're using an array here. `Set.of` seems more suitable and will also check for duplicate entries.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ControlPropertiesTest.java line 232:

> 230:     private String err(Method method, String message) {
> 231:         return method + " " + message;
> 232:     }

(This comment didn't appear in the review for some reason.)

I think that the code could be a bit more clean. I took a stab at it:


    Set<Class<?>> CLASSES = Set.of(/*...*/);

    private void check(Class<?> cls) {
        Map<String, Method> methods = Stream.of(cls.getMethods()).collect(Collectors.toMap(Method::getName, m -> m)); // the loop is also fine
        
        for (var method : methods.values()) {
            String name = method.getName();
            if (name.endsWith("Property")) {
                checkModifiers(method);

                String propName = name.substring(0, name.length() - "Property".length());
                check(methods, propName, "get", 0);
                check(methods, propName, "set", 1);
                check(methods, propName, "is", 0);
            }
        }
    }

    private void check(Map<String, Method> methods, String name, String prefix, int numArgs) {
        String methodName = new StringJoiner("", prefix, name.substring(0, 1).toUpperCase() + name.substring(1)).toString();

        Method m = methods.get(methodName);
        if (m != null && m.getParameterCount() == numArgs) {
            checkModifiers(m);
        }
    }

    private void checkModifiers(Method m) {
        int mod = m.getModifiers();
        if (Modifier.isPublic(mod) && !Modifier.isFinal(mod)) {
            if (FAIL_FAST) {
                throw new AssertionError(errorMessage(m));
            } else {
                System.err.println(errorMessage(m));
            }
        }
    }

    private String errorMessage(Method method) {
        return method + "is not final";
    }

-------------

PR Review Comment: https://git.openjdk.org/jfx/pull/1213#discussion_r1299310658
PR Review Comment: https://git.openjdk.org/jfx/pull/1213#discussion_r1299310698
PR Review Comment: https://git.openjdk.org/jfx/pull/1213#discussion_r1299311517
PR Review Comment: https://git.openjdk.org/jfx/pull/1213#discussion_r1299436111


More information about the openjfx-dev mailing list