On Fri, 19 Dec 2025 20:56:27 GMT, Michael Strauß <[email protected]> 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

Reply via email to