Proposal: Deprecate Builders

Ali Ebrahimi ali.ebrahimi1781 at gmail.com
Mon Mar 25 13:01:13 PDT 2013


Hi Richard,
Today is the day I predicted two years ago and proposed alternative for
Builders.
this is : https://javafx-jira.kenai.com/browse/RT-13851

Best regards,
Ali Ebrahimi

On Mon, Mar 25, 2013 at 10:05 PM, Richard Bair <richard.bair at oracle.com>wrote:

> We made a mistake. When we released JavaFX 2.0 we included a (large) set
> of *Builder classes to provide a builder-pattern approach to building
> JavaFX UIs. The builder-pattern approach provides several very nice
> features:
>         - Ability to setup generic configuration once and "stamp out"
> multiple copies
>         - Structured code style that closely approximates the "container
> hierarchy" of the UI
>         - Strongly-typed "declarative" style programming
>
> The Builders did come at a cost. There are a lot of them, and if used,
> require more class loading which slows down startup. When Pack200 is not
> being used, they represent a sizable fraction of the code base. They
> clutter up the JavaDoc (although this could be solved by having a "Builder"
> section like there is an "Enum" section and "Interface" section).
>
> But all those advantages and costs were weighed and we concluded Builders
> were worth it, and they went in. Based on the above, I would still conclude
> that Builders are OK. However, it turns out our implementation has some
> intractable problems with respect to binary compatibility.
>
> In order to ensure our Builders are always up-to-date with the latest API
> added to the core classes, the Builders are auto-generated using an
> annotation processor. Also, in order to keep the size of the builders small
> relative to the rest of the platform, we employ complex use of generics in
> order to allow the builders to inherit. That is, ControlBuilder extends
> from ParentBuilder extends from NodeBuilder just as Control extends from
> Parent extends from Node. But accomplishing this was no easy feat. Although
> the "id(String)" method is defined on NodeBuilder, it must return a
> ControlBuilder when used from the ControlBuilder. All of this was
> accomplished using generics, and as it turns out, depended on two bugs in
> JDK 6 and JDK 7 in order to work (although we didn't know it at the time).
> Those bugs were fixed in JDK 8, and as a result, the builders no longer
> work correctly for certain cases. Just about any option we take is going to
> lead to a binary incompatibility in 8, however we find this unacceptable.
> If we cannot avoid it, then whatever we choice we make for 8 had better be
> a final solution -- not something we will later decide we need to tweak
> further.
>
> And this is what puts us in a tight spot. After having painfully looked
> over all of the alternatives, it seems to come down to this:
>         a) Flatten the builder hierarchy so that ControlBuilder extends
> Object the same as ParentBuilder would and all other Builders.
>         b) Stop using builders. Phase them out in a controlled manner.
>
> Option (a) works because we remove all generics from the equation. There
> are some 73 or so methods on NodeBuilder. These would be redefined on the
> Builder for each class that extends from Node. This solution works by
> solving the root problem -- generic use in builder subclassing scenarios.
> This solution however changes the cost/benefit analysis for Builders,
> because now they would then comprise a much larger fraction of the overall
> platform size. And this runs at cross purposes with embedded use cases.
>
> Option (b) works by removing Builders from the scenario entirely. Because
> this would be a *huge* breaking change, it would have to be managed
> carefully in a way that, in fact, won't break anybody (for at least several
> years). To implement this option, we would:
>         1) Add @Deprecate to all Builders with a URL in the description to
> a page describing the change and how to migrate
>         2) Stop auto-generating builders. We'd take whatever we had in the
> latest 2.x line and reuse them as-is.
>                 - This means that as new API is added to the platform, the
> builders wouldn't be updated to match
>         3) Remove the Builders from the Java 8 JavaDoc
>         4) Split the builders into a separate jar from jfxrt.jar. It would
> also be on the java.ext.libs path so that it is automatically picked up so
> that people are not broken when running FX 2.x apps on 8.x without
> modification. They'd still work.
>         5) Provide a download link to the fx2-builders.jar containing all
> these builders.
>         6) Encourage people to use fx2-builders.jar instead of relying on
> builders being on the class path by default
>         7) In Java 9, remove the builders from the class path (this is
> several years down the road)
>
> This proposal is essentially saying that the fix to make Builders work
> correctly reduces the value of the builders to the point where they just
> aren't worth it, and when considering Mobile / Embedded use cases, the
> extra cost of the builders is prohibitive. It also is based on the theory
> that the Builders are not being used by everybody, and so many people would
> not be negatively impacted but rather only positively impacted by no longer
> paying for the additional cost in bytes for the builders. It also
> recognizes that people who *are* using the builders and *do* like the
> programming style (including Jasper and many of our own) will see a loss of
> functionality that they have grown to like.
>
> The other thing to bear in mind is that most of the benefits of Builders
> don't have to come from Builders -- there are alternatives. For example,
> the 'Ability to setup generic configuration once and "stamp out" multiple
> copies' benefit can also be achieved by helper methods.  The 'Structured
> code style that closely approximates the "container hierarchy" of the UI'
> advantage can be accomplished using FXML instead, or by using this pattern
> (which creates a boat-load of inner classes so it has its own problems):
>
> // The first set of braces defines it as an anonymous subclass, the second
> set as an initializer
> Group g = new Group() {{
>     getChildren().add(new Button() {{
>         setText("Hello");
>     }});
> }};
>
> Another option which we've discussed a bit is whether we could use
> lambda's to do configuration in a builder-like style in Java 8, somewhat
> like Groovy does. So for example:
>
> Group g = new Group(gg -> {
>     gg.getChildren().addAll(new Button(b -> {
>         b.setText("Hello");
>     });
> });
>
> This approach doesn't generate the mass of anonymous inner classes that
> the other double-brace approach does, but accomplishes the same basic job
> of using builders for (more or less) declarative construction of a
> container-hierarchy in code.
>
> So this is the long and the short of it. Eva can follow up with an
> in-depth post about the binary compatibility concerns if you wish. My
> proposal after having weighed the options is to phase out the Builders by
> deprecating them in 8 and removing them from the class path in 9. I believe
> that FXML or Lambda's or alternative languages all provide other avenues
> for achieving the same goals as builders but without the additional cost in
> byte codes or classes.
>
> We have some cases where SceneBuilder is presently relying on the
> Builders, and we'd have to provide alternatives for that functionality it
> is presently using (such as annotations for constructor arguments).
>
> Richard


More information about the openjfx-dev mailing list