On Tue, 30 Jun 2026 20:29:44 GMT, Marius Hanl <[email protected]> wrote:
>> Mostly wondering the same - why do we have `ArrayListWrapper` but no wrapper
>> classes for the other collections? Maybe we can unify / simplify it more.
>>
>> I did some tests with `@NamedArg` and it really seems to be buggy with more
>> advanced usecases like this one
>
> @stechy1 do you have an idea about this?
> Since you are most likely the person that knows the most about this logic.
> Will help us a lot to review the change
I'm not an expert on this. I just start digging into this because `@NamedArg`
was not working as expected. The author of this piece of code must had a reason
to write it in this way.
`getReadOnlyProperty(propName)` - inspects the getter's return type and creates
a temporary container of the appropriate type (`ObservableList` ,
`ObservableSet` , `Map` , `Set` , or `ArrayListWrapper` for a plain
`Collection` ). Returns `null` if the property is not a read-only
collection/map.
This method is called here:
/**
* This is used to support read-only collection property. This method must
* return a Collection of the appropriate type if 1. the property is
* read-only, and 2. the property is a collection. It must return null
* otherwise.
*
*/
private Object getTemporaryContainer(String propName) {
Object o = containers.get(propName);
if (o == null) {
o = getReadOnlyProperty(propName);
if (o != null) {
containers.put(propName, o);
}
}
return o;
}
---
Methods `getTemporaryContainer()` and `getUserValue()` are in some kind of
relationship. We can look on this as two phases:
# Phase 1 - Parsing / accumulation
ProxyBuilder extends Map<String, Object> . While the FXML loader is parsing
child elements, it calls the standard Map methods containsKey(key) and
get(key) on the builder. Both of those override methods delegate directly to
getTemporaryContainer :
@Override
public boolean containsKey(Object key) {
return (getTemporaryContainer(key.toString()) != null);
}
@Override
public Object get(Object key) {
return getTemporaryContainer(key.toString()); // ← returns the temp
container
}
The FXML loader gets back the temporary container (e.g. `ArrayListWrapper` ,
`ObservableList` …), and populates it with the child elements.
# Phase 2 - Build / resolution
When FXML parsing is done, the loader calls `build()`. At that point:
1. All accumulated _containers_ are flushed into `userValues`.
2. The builder tries to find the best matching constructor / setters.
3. `getUserValue` is called for each parameter/property to retrieve the final,
correctly-typed value - including the `ArrayListWrapper` → scalar unwrapping
logic.
-------------
PR Review Comment: https://git.openjdk.org/jfx/pull/2167#discussion_r3518783450