Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package javafx.beans.property;

/**
* Marker interface for attached properties.
* <p>
* An attached property is {@linkplain ReadOnlyProperty#getDeclaringClass() declared} on one class, but associated
* with instances of another class (referred to as the <em>target</em> class). It is usually used to describe an
* aspect about the target <em>as it relates to</em> the declaring class. Property implementations that represent
* attached properties must implement this interface to expose the class of objects the property can be attached to.
* <p>
* Attached properties are typically exposed via a set of static methods on the declaring class. By convention,
* the property accessor is named {@code <propertyName>Property} and takes a single parameter with an instance
* of the target class. In addition, a convenience getter and setter is added:
* <pre>{@code
* class MyContainer {
* // Property accessor
* public static ObjectProperty<Insets> marginProperty(Node target);
*
* // Convenience getter, may elide property instantiation
* public static Insets getMargin(Node target);
*
* // Convenience setter, may elide property instantiation
* public static void setMargin(Node target, Insets value);
* }
* }</pre>
* Calling the property accessor must instantiate the property for the target object and store it in the target
* object for future retrieval. Implementations may use lazy instantiation mechanisms for the getter/setter
* methods; in particular, they might elide the instantiation of the property instance if the property accessor
* was not called before.
* <p>
* Note that the {@code AttachedProperty} interface might not be visible in the static type of the property, so
* a dynamic test via {@code instanceof AttachedProperty} might be required at runtime to detect its presence.
*
* @since 27
*/
public interface AttachedProperty {

/**
* Returns the class of objects to which this property can be attached.
*
* @return the target class
*/
Class<?> getTargetClass();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -38,48 +38,67 @@ public class ReadOnlyBooleanWrapper extends SimpleBooleanProperty {
private ReadOnlyPropertyImpl readOnlyProperty;

/**
* The constructor of {@code ReadOnlyBooleanWrapper}
* The constructor of {@code ReadOnlyBooleanWrapper}.
*/
public ReadOnlyBooleanWrapper() {
}

/**
* The constructor of {@code ReadOnlyBooleanWrapper}
* The constructor of {@code ReadOnlyBooleanWrapper}.
*
* @param initialValue
* the initial value of the wrapped value
* @param initialValue the initial value
*/
public ReadOnlyBooleanWrapper(boolean initialValue) {
super(initialValue);
}

/**
* The constructor of {@code ReadOnlyBooleanWrapper}
* The constructor of {@code ReadOnlyBooleanWrapper}.
*
* @param bean
* the bean of this {@code ReadOnlyBooleanProperty}
* @param name
* the name of this {@code ReadOnlyBooleanProperty}
* @param bean the bean of this property
* @param name the name of this property
*/
public ReadOnlyBooleanWrapper(Object bean, String name) {
super(bean, name);
}

/**
* The constructor of {@code ReadOnlyBooleanWrapper}
* The constructor of {@code ReadOnlyBooleanWrapper}.
*
* @param bean
* the bean of this {@code ReadOnlyBooleanProperty}
* @param name
* the name of this {@code ReadOnlyBooleanProperty}
* @param initialValue
* the initial value of the wrapped value
* @param bean the bean of this property
* @param name the name of this property
* @param initialValue the initial value
*/
public ReadOnlyBooleanWrapper(Object bean, String name,
boolean initialValue) {
super(bean, name, initialValue);
}

/**
* The constructor of {@code ReadOnlyBooleanWrapper}.
*
* @param bean the bean of this property
* @param declaringClass the class in which this property is declared
* @param name the name of this property
* @since 27
*/
public ReadOnlyBooleanWrapper(Object bean, Class<?> declaringClass, String name) {
super(bean, declaringClass, name);
}

/**
* The constructor of {@code ReadOnlyBooleanWrapper}.
*
* @param bean the bean of this property
* @param declaringClass the class in which this property is declared
* @param name the name of this property
* @param initialValue the initial value
* @since 27
*/
public ReadOnlyBooleanWrapper(Object bean, Class<?> declaringClass, String name, boolean initialValue) {
super(bean, declaringClass, name, initialValue);
}

/**
* Returns the readonly property, that is synchronized with this
* {@code ReadOnlyBooleanWrapper}.
Expand All @@ -88,7 +107,9 @@ public ReadOnlyBooleanWrapper(Object bean, String name,
*/
public ReadOnlyBooleanProperty getReadOnlyProperty() {
if (readOnlyProperty == null) {
readOnlyProperty = new ReadOnlyPropertyImpl();
readOnlyProperty = this instanceof AttachedProperty
? new AttachedReadOnlyPropertyImpl()
: new ReadOnlyPropertyImpl();
}
return readOnlyProperty;
}
Expand Down Expand Up @@ -120,5 +141,18 @@ public Object getBean() {
public String getName() {
return ReadOnlyBooleanWrapper.this.getName();
}

@Override
public Class<?> getDeclaringClass() {
return ReadOnlyBooleanWrapper.this.getDeclaringClass();
}
}

private class AttachedReadOnlyPropertyImpl extends ReadOnlyPropertyImpl implements AttachedProperty {

@Override
public Class<?> getTargetClass() {
return ((AttachedProperty)ReadOnlyBooleanWrapper.this).getTargetClass();
}
}
Comment on lines +151 to 157
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is clumsier than I had hoped.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's okay as it's a very localized implementation detail. You'll probably forget that it even exists very soon and move on.

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -38,48 +38,67 @@ public class ReadOnlyDoubleWrapper extends SimpleDoubleProperty {
private ReadOnlyPropertyImpl readOnlyProperty;

/**
* The constructor of {@code ReadOnlyDoubleWrapper}
* The constructor of {@code ReadOnlyDoubleWrapper}.
*/
public ReadOnlyDoubleWrapper() {
}

/**
* The constructor of {@code ReadOnlyDoubleWrapper}
* The constructor of {@code ReadOnlyDoubleWrapper}.
*
* @param initialValue
* the initial value of the wrapped value
* @param initialValue the initial value
*/
public ReadOnlyDoubleWrapper(double initialValue) {
super(initialValue);
}

/**
* The constructor of {@code ReadOnlyDoubleWrapper}
* The constructor of {@code ReadOnlyDoubleWrapper}.
*
* @param bean
* the bean of this {@code ReadOnlyDoubleProperty}
* @param name
* the name of this {@code ReadOnlyDoubleProperty}
* @param bean the bean of this property
* @param name the name of this property
*/
public ReadOnlyDoubleWrapper(Object bean, String name) {
super(bean, name);
}

/**
* The constructor of {@code ReadOnlyDoubleWrapper}
* The constructor of {@code ReadOnlyDoubleWrapper}.
*
* @param bean
* the bean of this {@code ReadOnlyDoubleProperty}
* @param name
* the name of this {@code ReadOnlyDoubleProperty}
* @param initialValue
* the initial value of the wrapped value
* @param bean the bean of this property
* @param name the name of this property
* @param initialValue the initial value
*/
public ReadOnlyDoubleWrapper(Object bean, String name,
double initialValue) {
super(bean, name, initialValue);
}

/**
* The constructor of {@code ReadOnlyDoubleWrapper}.
*
* @param bean the bean of this property
* @param declaringClass the class in which this property is declared
* @param name the name of this property
* @since 27
*/
public ReadOnlyDoubleWrapper(Object bean, Class<?> declaringClass, String name) {
super(bean, declaringClass, name);
}

/**
* The constructor of {@code ReadOnlyDoubleWrapper}.
*
* @param bean the bean of this property
* @param declaringClass the class in which this property is declared
* @param name the name of this property
* @param initialValue the initial value
* @since 27
*/
public ReadOnlyDoubleWrapper(Object bean, Class<?> declaringClass, String name, double initialValue) {
super(bean, declaringClass, name, initialValue);
}

/**
* Returns the read-only property, that is synchronized with this
* {@code ReadOnlyDoubleWrapper}.
Expand All @@ -88,7 +107,9 @@ public ReadOnlyDoubleWrapper(Object bean, String name,
*/
public ReadOnlyDoubleProperty getReadOnlyProperty() {
if (readOnlyProperty == null) {
readOnlyProperty = new ReadOnlyPropertyImpl();
readOnlyProperty = this instanceof AttachedProperty
? new AttachedReadOnlyPropertyImpl()
: new ReadOnlyPropertyImpl();
}
return readOnlyProperty;
}
Expand Down Expand Up @@ -120,5 +141,18 @@ public Object getBean() {
public String getName() {
return ReadOnlyDoubleWrapper.this.getName();
}

@Override
public Class<?> getDeclaringClass() {
return ReadOnlyDoubleWrapper.this.getDeclaringClass();
}
}

private class AttachedReadOnlyPropertyImpl extends ReadOnlyPropertyImpl implements AttachedProperty {

@Override
public Class<?> getTargetClass() {
return ((AttachedProperty)ReadOnlyDoubleWrapper.this).getTargetClass();
}
}
}
Loading