<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>You mean using an annotation processor?</p>
    <p>These can actually only create new types; modifying an existing
      one like Lombok is doing is illegal (the original source code with
      Lombok annotations is not plain Java anymore, hence an IDE plugin
      is required for IDE's to understand it).</p>
    <p>Still, a lot is possible.  I really like RecordBuilder
      (<a class="moz-txt-link-freetext" href="https://github.com/Randgalt/record-builder">https://github.com/Randgalt/record-builder</a>) -- it provide
      builders for records (in a seperate type named
      <recordName>`Builder`) and if your record implements
      <recordName>`Builder.With`, you even get wither methods
      courtesy of the default methods on the generated interface
      <recordName>`Builder.With`.</p>
    <p>--John<br>
    </p>
    On 06/12/2023 14:42, Thiago Milczarek Sayão wrote:<br>
    <blockquote type="cite"
cite="mid:CAAP_wumMP0uTX9xvQdL3HDe+ed-sjD=jb8PxfJWc-2KX1LZ8qA@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="ltr">Hi,
        <div><br>
        </div>
        <div>Maybe it could generate the boilerplate like Lombok does?</div>
        <div>So it has the benefits of eliminating error-prone
          boilerplate code and the benefits of not having the cost of
          reflection at runtime.<br>
        </div>
        <div><br>
        </div>
        <div>-- Thiago.</div>
        <div><br>
        </div>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">Em qua., 6 de dez. de 2023 às
          10:28, John Hendrikx <<a
            href="mailto:john.hendrikx@gmail.com" target="_blank"
            moz-do-not-send="true" class="moz-txt-link-freetext">john.hendrikx@gmail.com</a>>
          escreveu:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px
          0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div>
            <p>I also like this route, perhaps slightly more, depending
              on how far this can be taken:<br>
            </p>
            <p>Disclaimer: I dislike the CSSMetaData and special
              property subclass a lot -- it's a major concession to make
              properties work with the CSS system that brings a lot of
              boilerplate that is mostly unnecessary.</p>
            <p>If you go the route of an annotation, we could offer to
              do everything via the annotation so a regular property can
              be converted to styleable by annotating it.  The property
              would then have to specify the name ("-fx-label-padding")
              and the default value (which can be a string that is
              parseable via the existing CSS parser).</p>
            <p>In other words:</p>
            <p><span
                style="background-color:rgb(255,255,255);padding:0px 0px
                0px 2px"><span style="color:rgb(0,0,0);background-color:rgb(255,255,255);font-family:Consolas;font-size:11pt;white-space:pre-wrap"><span style="color:rgb(0,0,0)"></span><span style="color:rgb(0,0,160);font-weight:bold">    @Styleable(name = "-fx-label-padding", defaultValue = "(0, 0, 0, 0)")
    public</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,160);font-weight:bold">final</span><span style="color:rgb(0,0,0)"> ReadOnlyObjectProperty<Insets> labelPaddingProperty() { ... }</span></span></span></p>
            <div>The rest the scanner can figure out (it could even
              figure out a default name). The `isSettable` method is
              always the same boilerplate (and if not, you can use the
              old way).  The required converter can be derived from the
              generic type (Insets -> InsetsConverter), or specified
              (converter = InsetsConverter.class).</div>
            <div><br>
            </div>
            <div>To convert a regular property into a styleable does
              require somewhat more magic (the CSS system would have to
              wrap it, or otherwise track them) but that's all hidden. 
              It gets rid of the StyleableProperty uglyness and the need
              for users to create those, and puts the "extra"
              CSSMetaData information a styleable property needs firmly
              where it belongs (in an annotation).</div>
            <br>
            <div>--John<br>
            </div>
            <div><br>
            </div>
            <div>On 06/12/2023 11:37, Nir Lisker wrote:<br>
            </div>
            <blockquote type="cite">
              <div dir="ltr">I thought about the option of reflection,
                but I opted to propose annotations instead. The
                following is my reasoning.
                <div><br>
                </div>
                <div>Firstly, reflection is very magic-y. The author of
                  the class has no indication of what side effects
                  happen due to the code they write, the output (css
                  handling in this case) comes out of nowhere from their
                  perspective. As with other reflection cases, it is a
                  "pull" rather than "push" approach - you don't write
                  what should happen, you let someone else decide that.
                  For writers of skin/control classes, this means that
                  they need to know exactly what constitutes a hook for
                  the reflection mechanism, or face surprises. There is
                  no compile time check that tells you whether you have
                  declared your styleable property properly or not
                  (without an external ad-hoc checker).</div>
                <div>We do this somewhat with properties - any method of
                  the form "...property()" gets special treatment, but
                  this is for the docs. I don't think we have code that
                  depends on this other than in tests.</div>
                <div><br>
                </div>
                <div>Secondly, the proposed mechanism depends on the
                  runtime type, not the declared type. As a user, I see
                  no indication in the API whether a property is
                  styleable or not. This is also (what I would consider)
                  a problem with the current state. When I thought about
                  using reflection to solve this, I at least thought to
                  specify the declared type of the property as
                  styleable, like StyleableBooleanProperty instead of
                  BooleanProperty (restricting the returned type is
                  backwards compatible). A downside of this is that it
                  gives access to the methods of StyleableProperty,
                  which are not useful for the user, I think, but maybe
                  someone has a use for them.</div>
                <div><br>
                </div>
                <div>Thirdly, maybe I want to declare a styleable
                  property not to be used automatically. I can't think
                  off the top of my head when I would want to do that,
                  but I'm also not a heavy css user. Are we sure that
                  just initializing a property with a styleable runtime
                  type should *always* be caught by this process?</div>
                <div><br>
                </div>
                <div>To compare, annotations have the following
                  benefits:</div>
                <div><br>
                </div>
                <div>Firstly, they are declarative, which means no
                  surprises for the class author (WYSIWYG). This also
                  allows more flexibility/control over which properties
                  get special treatment via an opt-in mechanism.</div>
                <div><br>
                </div>
                <div>Secondly, They can also be displayed in the
                  JavaDocs (via @Documented) with their assigned values.
                  For example, the padding property of Region can be
                  annotated with @Styleable(property="-fx-padding"),
                  informing the user both that this value can be set by
                  css, and how to do it. Interestingly, the annotation
                  doesn't need to be public API to be displayed, so we
                  are not bound by contracts.<br>
                </div>
                <div><br>
                </div>
                <div>In terms of similarities:</div>
                <div><br>
                </div>
                <div>In both the reflection and the annotation
                  proposals, the steps are:</div>
                1. Create styleable properties.<br>
                2. That's it.
                <div>It's just that step 1 also adds an annotation to
                  the creation of the property (which was/is a 2-step
                  process anyway, declaring the property and its css
                  metadata).<br>
                </div>
                <div><br>
                </div>
                <div>Annotations also require a processor to read the
                  data from their values and target (the field/method).
                  This is a bit of work, but Michael's CssMetaDataCache
                  class is basically that - read the data from the class
                  (via reflection or annotations) and store it in a map.
                  The logic should be the same, just the method to
                  obtain the data is different. Both, as a result, have
                  the benefits of handling control/skin combinations
                  (what I mentioned in the point "<span
                    style="color:rgb(232,230,227)">Usable both in
                    controls and in skins (or other classes)")</span>.</div>
                <div><br>
                </div>
                <div>The benefit of co-locating the property and its css
                  metadata in the class itself also remains.</div>
                <div><br>
                </div>
                <div><br>
                </div>
                <div>To summarize, both approaches eliminate all the
                  clutter of writing styleable properties (John, will
                  you like to create styleable properties now? [1] :) ),
                  both apply the flexibility of caching per class, both
                  allow better structuring of the class, but they read
                  the properties differently and have a different level
                  of declarativness.</div>
                <div><br>
                </div>
                <div>[1] <a
href="https://mail.openjdk.org/pipermail/openjfx-dev/2023-December/044010.html"
                    target="_blank" moz-do-not-send="true"
                    class="moz-txt-link-freetext">https://mail.openjdk.org/pipermail/openjfx-dev/2023-December/044010.html</a></div>
                <div><br>
                </div>
              </div>
              <br>
              <div class="gmail_quote">
                <div dir="ltr" class="gmail_attr">On Tue, Dec 5, 2023 at
                  11:21 PM Andy Goryachev <<a
                    href="mailto:andy.goryachev@oracle.com"
                    target="_blank" moz-do-not-send="true"
                    class="moz-txt-link-freetext">andy.goryachev@oracle.com</a>>
                  wrote:<br>
                </div>
                <blockquote class="gmail_quote" style="margin:0px 0px
                  0px 0.8ex;border-left:1px solid
                  rgb(204,204,204);padding-left:1ex">
                  <div>
                    <div lang="EN-US">
                      <div>
                        <p class="MsoNormal"><span>I like the idea.</span></p>
                        <p class="MsoNormal"><span> </span></p>
                        <p class="MsoNormal"><span>I wonder if it is
                            possible to reduce the amount of boilerplate
                            code?  For example, a CssMetaData can have a</span></p>
                        <p class="MsoNormal"><span> </span></p>
                        <p class="MsoNormal" style="text-indent:0.5in"><span>setGetter(Function<S,
                            StyleableProperty<V>> getter)</span></p>
                        <p class="MsoNormal"><span> </span></p>
                        <p class="MsoNormal"><span>method which supplies
                            the property reference?  This way
                            CssMetaData.isSettable(Node) and
                            CssMetaData.getStyleableProperty(Node) can
                            be implemented in the base class (there are
                            more complicated cases, so perhaps
                            setIsSettable(Predicate<Node>) would
                            also be required).</span></p>
                        <p class="MsoNormal"><span> </span></p>
                        <p class="MsoNormal"><span>Example:</span></p>
                        <p class="MsoNormal"><span> </span></p>
                        <p class="MsoNormal"
                          style="background:rgb(232,242,254)"><span
                            lang="FR">CssMetaData.<ControlExample,Font>of(</span><span
                            lang="FR">"-fx-font"</span><span lang="FR">,
                            Font.getDefault(), (n) -> n.font)</span></p>
                        <p class="MsoNormal"><span lang="FR"> </span></p>
                        <p class="MsoNormal"><span>Just a thought.  What
                            do you think?</span></p>
                        <p class="MsoNormal"><span> </span></p>
                        <p class="MsoNormal"><span>-andy</span></p>
                        <p class="MsoNormal"><span> </span></p>
                        <p class="MsoNormal"><span> </span></p>
                        <div
id="m_6823917702071497988m_-5766188174560428208m_-7571650920342053996m_640328469919311222m_-4650580218595929338mail-editor-reference-message-container">
                          <div>
                            <div
style="border-right:none;border-bottom:none;border-left:none;border-top:1pt
                              solid rgb(181,196,223);padding:3pt 0in
                              0in">
                              <p class="MsoNormal"
                                style="margin-bottom:12pt"><b><span
                                    style="font-size:12pt;color:black">From:
                                  </span></b><span
                                  style="font-size:12pt;color:black">openjfx-dev
                                  <<a
                                    href="mailto:openjfx-dev-retn@openjdk.org"
                                    target="_blank"
                                    moz-do-not-send="true"
                                    class="moz-txt-link-freetext">openjfx-dev-retn@openjdk.org</a>>
                                  on behalf of Michael Strauß <<a
                                    href="mailto:michaelstrau2@gmail.com"
                                    target="_blank"
                                    moz-do-not-send="true"
                                    class="moz-txt-link-freetext">michaelstrau2@gmail.com</a>><br>
                                  <b>Date: </b>Sunday, December 3, 2023
                                  at 22:02<br>
                                  <b>To: </b>openjfx-dev <<a
                                    href="mailto:openjfx-dev@openjdk.org"
                                    target="_blank"
                                    moz-do-not-send="true"
                                    class="moz-txt-link-freetext">openjfx-dev@openjdk.org</a>><br>
                                  <b>Subject: </b>Reflective discovery
                                  of styleable properties</span></p>
                            </div>
                            <div>
                              <p class="MsoNormal"><span
                                  style="font-size:11pt">Following up
                                  the discussion around the CssMetaData
                                  API, I'd like to<br>
                                  chime in with yet another idea. To
                                  recap, here's Nir's summary of the<br>
                                  current API [0]:<br>
                                  <br>
                                  "Let's look at what implementation is
                                  required from a user who wants<br>
                                  to write their own styleable control:<br>
                                  1. Create styleable properties.<br>
                                  2. Create a list of these properties
                                  to be passed on.<br>
                                  3. Create a public static method that
                                  returns the concatenation of<br>
                                  this list with the one of its parent.
                                  (This method happens to be<br>
                                  poorly documented, as mstr said.)<br>
                                  4. Create a public non-static method
                                  that calls the static method in a<br>
                                  forced-override pattern because
                                  otherwise you will be calling the<br>
                                  wrong static method. (This method's
                                  docs seem to be just wrong because<br>
                                  you don't always want to delegate to
                                  Node's list.)"<br>
                                  <br>
                                  <br>
                                  I think this could reasonably be
                                  replaced with the following<br>
                                  implementation requirements:<br>
                                  1. Create styleable properties.<br>
                                  2. That's it.<br>
                                  <br>
                                  Let's look at what we're actually
                                  trying to do: create a list of<br>
                                  CSS-styleable property metadata of a
                                  class. But we can easily do that<br>
                                  without all of the boilerplate code.<br>
                                  <br>
                                  When ´Node.getCssMetaData()` is
                                  invoked, all public methods of the<br>
                                  class are reflectively enumerated, and
                                  metadata is retrieved from<br>
                                  `Property` and `StyleableProperty`
                                  getters. This is a price that's<br>
                                  only paid once for any particular
                                  class (i.e. not for every instance).<br>
                                  The resulting metadata list is cached
                                  and reused for all instances of<br>
                                  that particular class.<br>
                                  <br>
                                  As a further optimization, metadata
                                  lists are also cached and<br>
                                  deduplicated for Control/Skin
                                  combinations (currently every Control<br>
                                  instance has its own copy of the
                                  metadata list).<br>
                                  <br>
                                  Another benefit of this approach is
                                  that the CssMetaData can now be<br>
                                  co-located with the property
                                  implementation, and not be kept around
                                  in<br>
                                  other parts of the source code file.
                                  Here's how that looks like when a<br>
                                  new "myValue" property is added to
                                  MyClass:<br>
                                  <br>
                                      StyleableDoubleProperty myValue =<br>
                                              new
                                  SimpleStyleableDoubleProperty(this,
                                  "myValue") {<br>
                                  <br>
                                          static final
                                  CssMetaData<MyClass, Number>
                                  METADATA =<br>
                                              new
                                  CssMetaData<MyClass, Number>(<br>
                                                  "-fx-my-value",<br>
                                                 
                                  SizeConverter.getInstance(),<br>
                                                  USE_COMPUTED_SIZE) {<br>
                                              @Override<br>
                                              public boolean
                                  isSettable(MyClass node) {<br>
                                                  return
                                  !node.myValue.isBound();<br>
                                              }<br>
                                  <br>
                                              @Override<br>
                                              public StyleableProperty
                                  getStyleableProperty(<br>
                                                      MyClass node) {<br>
                                                  return node.myValue;<br>
                                              }<br>
                                          };<br>
                                  <br>
                                          @Override<br>
                                          public CssMetaData
                                  getCssMetaData() {<br>
                                              return METADATA;<br>
                                          }<br>
                                      };<br>
                                  <br>
                                      public final DoubleProperty
                                  myValueProperty() {<br>
                                          return myValue;<br>
                                      }<br>
                                  <br>
                                  It is not required to override the
                                  `getCssMetaData()` method, nor is<br>
                                  it required to redeclare a new static
                                  `getClassCssMetaData()` method.<br>
                                  It is also not required to manually
                                  keep the list of styleable<br>
                                  properties in sync with the list of
                                  CSS metadata.<br>
                                  <br>
                                  I've prototyped this concept for the
                                  `Node`, `Region` and `Control` classes
                                  [1].<br>
                                  <br>
                                  [0] <a
href="https://mail.openjdk.org/pipermail/openjfx-dev/2023-December/044046.html"
                                    target="_blank"
                                    moz-do-not-send="true"
                                    class="moz-txt-link-freetext">
https://mail.openjdk.org/pipermail/openjfx-dev/2023-December/044046.html</a><br>
                                  [1] <a
                                    href="https://github.com/openjdk/jfx/pull/1299"
                                    target="_blank"
                                    moz-do-not-send="true"
                                    class="moz-txt-link-freetext">https://github.com/openjdk/jfx/pull/1299</a></span></p>
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </blockquote>
              </div>
            </blockquote>
          </div>
        </blockquote>
      </div>
    </blockquote>
  </body>
</html>