RFR: 8375588: Enhanced property metadata

Michael Strauß mstrauss at openjdk.org
Mon Jan 19 03:47:06 UTC 2026


On Fri, 19 Dec 2025 20:56:27 GMT, Michael Strauß <mstrauss at openjdk.org> wrote:

> Implementation of [enhanced property metadata](https://gist.github.com/mstr2/2fec0303fc440b8eaeb126befc76eb5c).
> 
> ### New API
> This PR includes the following API additions:
> 
> 1. `ReadOnlyProperty.getDeclaringClass()` and its default implementation.
> 2. The `javafx.beans.property.AttachedProperty` interface.
> 3. New constructors for all `Simple<*>Property` and `ReadOnly<*>Wrapper` classes, accepting the declaring class of the property.
> 
> The declaring class is stored in a new field in the `Simple<*>Property` classes. If a legacy constructor is used that doesn't specify the declaring class, the `ReadOnlyProperty.getDeclaringClass()` default implementation is called the first time the `Simple<*>Property.getDeclaringClass()` method is called, and its result is stored for future retrieval.
> 
> ### Testing
> For testing, this PR also includes the `test.util.property.PropertyMetadataVerifier` tool. It systematically tests all public and protected properties of a class, and ensures conformance to the following rules:
> * `ReadOnlyProperty.getBean()` returns the object instance of the enclosing class, or the target object instance if the property is an attached property.
> *  `ReadOnlyProperty.getName()` returns the name of the property, which must correspond to the name of the property getter (excluding the word "Property").
> * `ReadOnlyProperty.getDeclaringClass()` returns the enclosing class of the property getter.
> * The declaring class of a `Simple<*>Property` or `ReadOnly<*>Wrapper` must be specified in the constructor, not resolved at runtime.
> * `getBean()`, `getName()`, and `getDeclaringClass()` must not be overridden in subclasses of `Simple<*>Property` or `ReadOnly<*>Wrapper`.
> * An instance property does not implement `AttachedProperty`.
> * An instance property has a parameterless property getter.
> * An attached property implements `AttachedProperty`.
> * An attached property has a static single-argument property getter that accepts the target object.
> * `AttachedProperty.getTargetClass()` returns the class of the single parameter of the static property getter.
> * A property getter does not return an instance of `ReadOnly<*>Wrapper`, it returns the result of calling `ReadOnly<*>Wrapper.getReadOnlyProperty()`.
> 
> Many properties in existing JavaFX classes violate the `PropertyMetadataVerifier` rules in some way or shape. This PR won't address these issues, this will be done in a future cleanup PR.

An attached property is a property whose semantics are defined by one class, but whose value is associated with instances of another class. In other words, the declaring class "owns" the meaning, but the associated object owns the value.

For example, `GridPane.columnIndex` doesn't describe anything about the `GridPane`; instead, it describes something about _another object_ as it relates to the `GridPane`. Another example is `HeaderBar.prefButtonHeight`, which is a property of `Stage`, but that property is only meaningful as it relates to `HeaderBar`.

This is not a parent/child relationship and it is not primarily about CSS, it's about meaning and context. For example, you could decorate arbitrary model objects with context-specific state: an entity could be "valid" as it relates to a specific validator or rule, it could be "selected" in a specific context, or it could carry metadata (constraints, tags, flags) that is only meaningful for a particular framework.

JavaFX already has this concept today, but we're not using the `Property` API to model it. Layout constraints like `GridPane.columnIndex` or `HBox.margin` are implemented as static getter/setter pairs. Since they are not first-class properties, you don't get any of the nice property features (bindings, listeners, styling, etc).

If we expose attached properties with the `Property` API and you want to introspect a property, "is this intrinsic to its bean, or is it contextual/constraint-like?" is a fundamental question. The `AttachedProperty` marker interface answers that question.

It's important to note that the attached property model does not come with a scope model. If I set `GridPane.columnIndex` on some child of `GridPane`, it doesn't lose that property just because it's removed from the `GridPane`. That would be a major complication that's also unexpected.

I removed the `ReadOnlyProperty.isAttached()` method, and instead added the `AttachedProperty` marker interface. It can not only be used to test whether a property is an attached property, but also answers the question to which kind of object it can be attached.

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

PR Comment: https://git.openjdk.org/jfx/pull/2015#issuecomment-3679800590
PR Comment: https://git.openjdk.org/jfx/pull/2015#issuecomment-3690623819


More information about the openjfx-dev mailing list