[
https://issues.apache.org/jira/browse/GROOVY-11434?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18128813#comment-18128813
]
ASF GitHub Bot commented on GROOVY-11434:
-----------------------------------------
daniellansun commented on PR #2989:
URL: https://github.com/apache/groovy/pull/2989#issuecomment-6270524639
# Code review: GROOVY-11434 groovy-groovyfx
Reviewed commits:
- `fcb630cc045950beb13d98ba4b016165db83590f` — add the optional
`groovy-groovyfx` module
- `229870fa64c56ce30986170a5e38340287177612` — put the compile-only JavaFX
jars on the reachability-metadata generator classpath
This note is from reading those commits and the surrounding builder and
transform code. The test suite was not re-run for this review.
## Recommendation
Please address the scene-root behavior before merging `fcb630cc04`. The
suggested scene change is small, and it brings the implementation in line with
`SceneFactory`'s own contract. The notes on numeric extensions and
`@FXBindable` are smaller; they are worth doing in the same change if that
stays convenient. `229870fa64` looks right as it stands.
## Design that fits the codebase
The module follows the `SwingBuilder` shape in the right places.
- `SceneGraphBuilder` registers one reflective `NodeFactory` for the common
node, and a separate factory only where construction itself differs: stage,
scene, charts, table columns, and `bind`.
- Child placement stays in `FXChildren`. That decision depends on the
parent, so one parent dispatch is easier to follow than a factory per control.
- `FXRuntime` names no JavaFX type, so a missing runtime can be reported
before those classes are linked.
- Toolkit startup distinguishes "already running" from "already shut down".
- JavaFX remains compile-only and is not bundled. The
GPL-2.0-with-Classpath-Exception dependency stays off the runtime classpath.
- No new source file approaches a thousand lines. `SceneGraphBuilder` is 544
lines.
Please keep that split. Moving child placement back into per-control
factories would add types without removing rules.
## Scene root is chosen before the sibling list is known
`SceneFactory` documents this rule: the first nested `Parent` becomes the
scene root; when the first child is not a `Parent`, or when further children
follow, those children belong to a `Group` root.
`setChild` applies a different rule. On the first `Parent` it clears
`groovyfx.placeholderRoot` and replaces `scene.root` immediately. A later
sibling is then appended to that root when the root is a `Group` or a `Pane`.
`VBox`, `HBox`, `BorderPane`, and `GridPane` are all `Pane`s, so this builder
nests the second child inside the first:
```groovy
scene {
vbox { label('a') }
label('b')
}
```
`label('b')` becomes a child of the `vbox`, beside `'a'`. Two panes, such as
`vbox` followed by `hbox`, nest the second pane inside the first. A later
sibling throws only when the replacement root is neither a `Group` nor a `Pane`.
`setChild` sees one child at a time, so it cannot know whether another
sibling will follow. The swap in `setChild` therefore cannot implement the
documented rule. `onNodeCompleted` already runs after the whole body.
Suggested behavior:
1. When no explicit `root:` is given, keep the placeholder `Group` for the
entire body and add every nested `Node` to it.
2. In `onNodeCompleted`, if that group contains exactly one child and that
child is a `Parent`, remove the child from the group and then set it as
`scene.root`. A node cannot have two parents, so the removal has to happen
first.
3. When the caller passed `root:`, keep adding children to that root, and
skip the promotion.
That leaves one completion rule in place of the mid-build swap, the "append
to a pane" branch, and the placeholder flag being cleared on the first parent.
Please add tests for a `vbox` followed by a `label`, and for two panes. In
both cases the children should be siblings under a `Group`. The current tests
cover a single `vbox` (`buildsAStageSceneAndControls`) and rectangles only
(`sceneWithoutParentRootGetsAGroup`). They do not cover a `Parent` with a
following sibling.
## Numeric extensions repeat one type dispatch
`FXExtensions` uses the same ladder in seven methods: `Integer`, `Short`, or
`Byte`, then `Long`, then `Float`, otherwise `doubleValue()`. The ladder
appears in `plus`, `minus`, and `div` for a constant on the right, and in
`plus`, `minus`, `multiply`, and `div` for a constant on the left.
The public overloads need to remain. Extension methods are selected by
signature. The bodies can share one private method that accepts the four
primitive operations (`int`, `long`, `float`, and `double`). `negative`, and
the overloads that only forward to `add` or `concat`, are already direct.
That ladder is also the numeric policy. `BigDecimal` and `BigInteger` match
none of the branches, so both become `doubleValue()`. An expression such as
`1.5g + property` therefore yields a `double` binding. Please make that choice
once, in the shared helper: either call the `Bindings` overload that preserves
the operand type, or reject a non-primitive `Number` with an exception that
states the conversion.
## `@FXBindable` maps types by simple name after resolution
`FXPropertyTypes.forType` classifies a property by its simple name. That is
appropriate for `FXBindableASTStubber`, which runs at `CONVERSION`, before
names are resolved. `FXBindableASTTransformation` runs at `CANONICALIZATION`,
after resolution. Please map resolved types there from the resolved `ClassNode`
(`ClassHelper` primitives, `java.lang.String`, `ObservableList`,
`ObservableMap`, and `ObservableSet`), and keep the simple-name table in the
stubber.
With the current shared function, any class whose simple name is `String`
becomes a `StringProperty`. The annotation contract lists `boolean`, `int`,
`long`, `float`, `double`, `String`, and their wrappers. `forType` also maps
`short`, `byte`, and `char` to `IntegerProperty`, because those names are in
`INTEGER_NAMES`. Storing a `char` as an `int` should be stated in that
contract, or the mapping should stop.
The generated `nameProperty()` method publishes the property with a
check-then-act on a non-volatile field: if `name$property` is null, it assigns
a new `Simple*Property`. Two threads can each construct a property, and the
write that loses drops listeners attached to the discarded instance. A model
filled off the JavaFX thread and then bound on it is a normal use of this
annotation. Please make the property field volatile and publish it under
synchronization, or generate the accessor as a synchronized method. The
getter's read of `name$property == null ? name : name$property.get()` has the
same visibility gap.
There is also no joint-compilation test showing that a Java caller can see
`nameProperty()` through the stub. The stubber exists for that phase.
## Smaller contracts
`XYChartFactory.newInstance` retains a positional value only when that value
is already an instance of the chart class. A call such as `lineChart('Sales')`
drops `'Sales'`. `StageFactory`, `SceneFactory`, and `NodeFactory` either use a
positional value or reject it. Please reject a non-chart positional value the
same way.
`NodeFactory.construct` catches every `GroovyRuntimeException` from
`invokeConstructorOf`. A constructor that runs and throws is reported as an
`InvokerInvocationException`, which is a `GroovyRuntimeException`. If the bean
also has a `text` property and the value is a `CharSequence`, that failure is
discarded and a no-argument instance receives `text`. Please catch
`MissingMethodException` for the text fallback, and let a constructor that has
already run propagate its failure.
## Classpath fix
`229870fa64` is the right fix, and it does not need a redesign.
`nativeImageMetadata` is a `JavaExec` task whose classpath is
`sourceSets.main.runtimeClasspath`. That classpath omits `compileOnly` and
`compileOnlyApi`. `FXExtensions` names `NumberBinding` in its signatures, so
`Class.getMethods()` needs the JavaFX jars. Appending
`configurations.compileClasspath` adds the configuration that contains them.
> Include GroovyFx in Apache Groovy
> ---------------------------------
>
> Key: GROOVY-11434
> URL: https://issues.apache.org/jira/browse/GROOVY-11434
> Project: Groovy
> Issue Type: New Feature
> Components: Swing
> Affects Versions: 4.0.22
> Reporter: Pruteanu Dragos
> Assignee: Paul King
> Priority: Major
> Fix For: 7.x
>
>
> Please include the project
> [GroovyFX|[http://groovyfx.org|http://groovyfx.org/]] into the Apache Groovy
> repository. The public repository is
> [here|https://github.com/groovyfx-project/groovyfx]. The project is very
> nice, something similar to groovy-swing. There has been no updates to that
> project, and there are compatibility issues with latest OpenJDKs.
> JavaFX is the highest standard regarding User Interfaces. The project is very
> nice and there are users interested in it.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)