You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by lk...@apache.org on 2022/05/30 21:13:26 UTC

[netbeans] branch master updated: Added support for properties backed up by functional interfaces

This is an automated email from the ASF dual-hosted git repository.

lkishalmi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new bfa926fee2 Added support for properties backed up by functional interfaces
bfa926fee2 is described below

commit bfa926fee2a7bf52574240c7981f15ba2cd57f29
Author: Laszlo Kishalmi <la...@gmail.com>
AuthorDate: Thu May 26 12:08:59 2022 -0700

    Added support for properties backed up by functional interfaces
---
 platform/openide.nodes/apichanges.xml              |  24 ++++
 .../src/org/openide/nodes/PropertySupport.java     | 135 +++++++++++++++++++--
 2 files changed, 147 insertions(+), 12 deletions(-)

diff --git a/platform/openide.nodes/apichanges.xml b/platform/openide.nodes/apichanges.xml
index 2c2fc5f6eb..300e1af5ec 100644
--- a/platform/openide.nodes/apichanges.xml
+++ b/platform/openide.nodes/apichanges.xml
@@ -25,6 +25,30 @@
 <apidef name="nodes">Nodes API</apidef>
 </apidefs>
 <changes>
+    <change id="PropertySupport.FunctionalProperty">
+        <api name="nodes"/>
+        <summary>Adding static methods to PropertySupport to allow easy creation
+            of properties using functional interfaces.
+        </summary>
+        <version major="7" minor="62"/>
+        <date day="26" month="5" year="2022"/>
+        <author login="lkishalmi"/>
+        <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible"/>
+        <description>
+            <a href="@TOP@/org/openide/nodes/PropertySupport.html">PropertySupport</a>
+            received a bunch of static methods (<code>readWrite</code>, <code>readOnly</code>, and
+            <code>writeOnly</code> to allow easy property creation with <code>Supplier</code> and
+            <code>Provider</code> functional interfaces.
+            <pre>
+                Sheet.Set set = ...
+                SomeObject obj = getLookup().lookup(SomeObject.class);
+
+                set.put(PropertySupport.readWrite("name", String.class, obj::getName, obj::setName));
+                set.put(PropertySupport.readOnly("size", Long.class, obj::getSize));
+            </pre>
+        </description>
+        <class package="org.openide.nodes" name="DestroyableNodesFactory"/>
+    </change>
     <change id="ChildFactory.DestroyableNodes">
         <api name="nodes"/>
         <summary>Adding ChildFactory.Detachable to allow ChildFactory implementations to
diff --git a/platform/openide.nodes/src/org/openide/nodes/PropertySupport.java b/platform/openide.nodes/src/org/openide/nodes/PropertySupport.java
index 3b5d42b526..a1b45fe7b2 100644
--- a/platform/openide.nodes/src/org/openide/nodes/PropertySupport.java
+++ b/platform/openide.nodes/src/org/openide/nodes/PropertySupport.java
@@ -26,13 +26,17 @@ import java.beans.PropertyEditor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
 import org.openide.util.Exceptions;
 import org.openide.util.NbBundle;
 
 /** Support class for <code>Node.Property</code>.
-*
-* @author Jan Jancura, Jaroslav Tulach, Ian Formanek
-*/
+ *
+ * @param <T> the type of the represented property.
+ *
+ * @author Jan Jancura, Jaroslav Tulach, Ian Formanek
+ */
 public abstract class PropertySupport<T> extends Node.Property<T> {
     /** flag whether the property is readable */
     private boolean canR;
@@ -62,6 +66,7 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
     * Returns the value passed into constructor.
     * @return <CODE>true</CODE> if the read of the value is supported
     */
+    @Override
     public boolean canRead() {
         return canR;
     }
@@ -70,6 +75,7 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
     * Returns the value passed into constructor.
     * @return <CODE>true</CODE> if the read of the value is supported
     */
+    @Override
     public boolean canWrite() {
         return canW;
     }
@@ -78,6 +84,7 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
      * Like {@link Class#cast} but handles primitive types.
      * See JDK #6456930.
      */
+    @SuppressWarnings("unchecked")
     static <T> T cast(Class<T> c, Object o) {
         if (c.isPrimitive()) {
             // Could try to actually type-check it, but never mind.
@@ -87,6 +94,79 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
         }
     }
 
+    /**
+     * Fluent wrapper method for {@link #setDisplayName(java.lang.String)}.
+     *
+     * @param displayName the display name to set.
+     * @since 7.62
+     *
+     * @return this instance
+     */
+    public final PropertySupport<T> withDisplayName(String displayName) {
+        setDisplayName(displayName);
+        return this;
+    }
+
+    /**
+     * Fluent wrapper method for {@link #setShortDescription(java.lang.String)}.
+     *
+     * @param shortDescription short description
+     * @since 7.62
+     * @return this instance
+     */
+    public final PropertySupport<T> withShortDescription(String shortDescription) {
+        setShortDescription(shortDescription);
+        return this;
+    }
+
+    /**
+     * Creates a "virtual" property where getter and setter are backed by the
+     * provided {@link Supplier} and {@link Consumer} functional interfaces.
+     * @param <T> the type of the property
+     * @param name the name of the property
+     * @param valueType the type of the property
+     * @param supplier the getter functional interface, can be {@code null} for write-only properties.
+     * @param consumer the setter functional interface, can be {@code null} for read-only properties.
+     *
+     * @since 7.62
+     * @return a {@link PropertySupport} instance where getter and setter are
+     *         backed by the provided functional interfaces.
+     */
+    public static <T> PropertySupport<T> readWrite(String name, Class<T> valueType, Supplier<T> supplier, Consumer<T> consumer) {
+        return new FunctionalProperty<>(name, valueType, supplier, consumer);
+    }
+
+    /**
+     * Creates a read-only "virtual" property where getter is backed by the
+     * provided {@link Supplier} functional interface.
+     * @param <T> the type of the property
+     * @param name the name of the property
+     * @param valueType the type of the property
+     * @param supplier the getter functional interface.
+     *
+     * @since 7.62
+     * @return a read-only {@link PropertySupport} instance where getter is
+     *         backed by the provided functional interface.
+     */
+    public static <T> PropertySupport<T> readOnly(String name, Class<T> valueType, Supplier<T> supplier) {
+        return new FunctionalProperty<>(name, valueType, supplier, null);
+    }
+    /**
+     * Creates a write-only "virtual" property where setter is backed by the
+     * provided {@link Consumer} functional interface.
+     * @param <T> the type of the property
+     * @param name the name of the property
+     * @param valueType the type of the property
+     * @param consumer the setter functional interface.
+     *
+     * @since 7.62
+     * @return a write-only {@link PropertySupport} instance where setter is
+     *         backed by the provided functional interface.
+     */
+    public static <T> PropertySupport<T> writeOnly(String name, Class<T> valueType, Consumer<T> consumer) {
+        return new FunctionalProperty<>(name, valueType, null, consumer);
+    }
+
     /**
      * Support for properties from Java Reflection.
      * Since 7.19, the {@link FeatureDescriptor#getName} will be set automatically.
@@ -213,7 +293,7 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
         }
 
         // Finds the proper getter
-        private static Method findGetter(Object instance, Class valueType, String property)
+        private static Method findGetter(Object instance, Class<?> valueType, String property)
         throws NoSuchMethodException {
             NoSuchMethodException nsme;
 
@@ -273,7 +353,7 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
                 }
             } catch (IllegalArgumentException iae) {
                 //Provide a better message for debugging
-                StringBuffer sb = new StringBuffer("Attempted to invoke method ");
+                StringBuilder sb = new StringBuilder("Attempted to invoke method ");
                 sb.append(getter.getName());
                 sb.append(" from class ");
                 sb.append(getter.getDeclaringClass().getName());
@@ -288,6 +368,7 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
         /* Can write the value of the property.
         * @return <CODE>true</CODE> if the read of the value is supported
         */
+        @Override
         public boolean canWrite() {
             return setter != null;
         }
@@ -298,6 +379,7 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
         * @exception IllegalArgumentException wrong argument
         * @exception InvocationTargetException an exception during invocation
         */
+        @Override
         public void setValue(T val)
         throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
             if (setter == null) {
@@ -322,14 +404,13 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
         * @return the property editor or <CODE>null</CODE> if there should not be
         *    any editor.
         */
+        @Override
         public PropertyEditor getPropertyEditor() {
             if (propertyEditorClass != null) {
                 try {
-                    return propertyEditorClass.newInstance();
-                } catch (InstantiationException ex) {
+                    return propertyEditorClass.getDeclaredConstructor().newInstance();
+                } catch (ReflectiveOperationException | SecurityException | IllegalArgumentException ex) {
                     Exceptions.printStackTrace(ex);
-                } catch (IllegalAccessException iex) {
-                    Exceptions.printStackTrace(iex);
                 }
             }
 
@@ -360,6 +441,35 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
         }
     }
 
+    private static final class FunctionalProperty<T> extends PropertySupport<T> {
+        private final Supplier<T> supplier;
+        private final Consumer<T> consumer;
+
+        public FunctionalProperty(String name, Class<T> type, Supplier<T> supplier, Consumer<T> consumer) {
+            super(name, type, null, null, supplier != null, consumer != null);
+            this.supplier = supplier;
+            this.consumer = consumer;
+        }
+
+        @Override
+        public T getValue() throws IllegalAccessException {
+            if (supplier != null) {
+                return supplier.get();
+            } else {
+                throw new IllegalAccessException("Cannod read from WriteOnly property"); // NOI18N
+            }
+        }
+
+        @Override
+        public void setValue(T val) throws IllegalAccessException {
+            if (consumer != null) {
+                consumer.accept(val);
+            } else {
+                throw new IllegalAccessException("Cannot write to ReadOnly property"); // NOI18N
+            }
+        }
+    }
+
     /** A simple read-only property.
     * Subclasses should implement {@link #getValue}.
     */
@@ -424,9 +534,8 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
         * @param node the node
         */
         public Name(final Node node) {
-            this(
-                node, NbBundle.getBundle(PropertySupport.class).getString("CTL_StandardName"),
-                NbBundle.getBundle(PropertySupport.class).getString("CTL_StandardHint")
+            this(node, NbBundle.getMessage(PropertySupport.class, "CTL_StandardName"),
+                NbBundle.getMessage(PropertySupport.class, "CTL_StandardHint")
             );
         }
 
@@ -443,6 +552,7 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
         /* Getter for the value. Delegates to Node.getName().
         * @return the name
         */
+        @Override
         public String getValue() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
             return node.getName();
         }
@@ -450,6 +560,7 @@ public abstract class PropertySupport<T> extends Node.Property<T> {
         /* Setter for the value. Delegates to Node.setName().
         * @param val new name
         */
+        @Override
         public void setValue(String val)
         throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
             Object oldName = node.getName();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists