Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotate Java Beans property listeners for nullness #123

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
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
20 changes: 12 additions & 8 deletions src/java.desktop/share/classes/java/beans/ChangeListenerMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
package java.beans;

import org.checkerframework.checker.interning.qual.UsesObjectEquals;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.qual.AnnotatedFor;
import org.checkerframework.framework.qual.CFComment;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -47,9 +50,10 @@
*
* @author Sergey A. Malenkov
*/
@AnnotatedFor({"interning"})
@CFComment("nullness: null values are permitted for property names, though not documented in Javadoc")
@AnnotatedFor({"interning", "nullness"})
abstract @UsesObjectEquals class ChangeListenerMap<L extends EventListener> {
private Map<String, L[]> map;
private @MonotonicNonNull Map<@Nullable String, L[]> map;

/**
* Creates an array of listeners.
Expand Down Expand Up @@ -78,7 +82,7 @@
* @param name the name of the property to listen on
* @param listener the listener to process events
*/
public final synchronized void add(String name, L listener) {
public final synchronized void add(@Nullable String name, L listener) {
if (this.map == null) {
this.map = new HashMap<>();
}
Expand All @@ -103,7 +107,7 @@ public final synchronized void add(String name, L listener) {
* @param name the name of the property to listen on
* @param listener the listener to process events
*/
public final synchronized void remove(String name, L listener) {
public final synchronized void remove(@Nullable String name, L listener) {
if (this.map != null) {
L[] array = this.map.get(name);
if (array != null) {
Expand Down Expand Up @@ -135,7 +139,7 @@ public final synchronized void remove(String name, L listener) {
* @param name the name of the property
* @return the corresponding list of listeners
*/
public final synchronized L[] get(String name) {
public final synchronized L[] get(@Nullable String name) {
return (this.map != null)
? this.map.get(name)
: null;
Expand All @@ -147,7 +151,7 @@ public final synchronized L[] get(String name) {
* @param name the name of the property
* @param listeners new list of listeners
*/
public final void set(String name, L[] listeners) {
public final void set(@Nullable String name, @Nullable L[] listeners) {
if (listeners != null) {
if (this.map == null) {
this.map = new HashMap<>();
Expand Down Expand Up @@ -196,7 +200,7 @@ public final synchronized L[] getListeners() {
* @param name the name of the property
* @return an array of listeners for the named property
*/
public final L[] getListeners(String name) {
public final L[] getListeners(@Nullable String name) {
if (name != null) {
L[] listeners = get(name);
if (listeners != null) {
Expand All @@ -214,7 +218,7 @@ public final L[] getListeners(String name) {
* @return {@code true} if at least one listener exists or
* {@code false} otherwise
*/
public final synchronized boolean hasListeners(String name) {
public final synchronized boolean hasListeners(@Nullable String name) {
if (this.map == null) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@

package java.beans;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.qual.AnnotatedFor;
import org.checkerframework.framework.qual.CFComment;

import java.io.Serial;

/**
Expand All @@ -43,6 +47,9 @@
* @since 1.5
* @author Mark Davidson
*/
@AnnotatedFor({"nullness"})
@CFComment({"nullness: don't permit null property name, class documentation may ",
"be a typo caused by cut-and-paste from PropertyChangeEvent"})
public class IndexedPropertyChangeEvent extends PropertyChangeEvent {

/**
Expand All @@ -67,7 +74,7 @@ public class IndexedPropertyChangeEvent extends PropertyChangeEvent {
* @param index index of the property element that was changed.
*/
public IndexedPropertyChangeEvent(Object source, String propertyName,
Object oldValue, Object newValue,
@Nullable Object oldValue, @Nullable Object newValue,
int index) {
super (source, propertyName, oldValue, newValue);
this.index = index;
Expand Down
26 changes: 15 additions & 11 deletions src/java.desktop/share/classes/java/beans/PropertyChangeEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
import java.io.Serial;
import java.util.EventObject;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.qual.AnnotatedFor;

/**
* A "PropertyChange" event gets delivered whenever a bean changes a "bound"
* or "constrained" property. A PropertyChangeEvent object is sent as an
Expand All @@ -47,6 +50,7 @@
*
* @since 1.1
*/
@AnnotatedFor({"nullness"})
public class PropertyChangeEvent extends EventObject {

/**
Expand All @@ -65,8 +69,8 @@ public class PropertyChangeEvent extends EventObject {
*
* @throws IllegalArgumentException if {@code source} is {@code null}
*/
public PropertyChangeEvent(Object source, String propertyName,
Object oldValue, Object newValue) {
public PropertyChangeEvent(Object source, @Nullable String propertyName,
@Nullable Object oldValue, @Nullable Object newValue) {
super(source);
this.propertyName = propertyName;
this.newValue = newValue;
Expand All @@ -79,7 +83,7 @@ public PropertyChangeEvent(Object source, String propertyName,
* @return The programmatic name of the property that was changed.
* May be null if multiple properties have changed.
*/
public String getPropertyName() {
public @Nullable String getPropertyName() {
return propertyName;
}

Expand All @@ -89,7 +93,7 @@ public String getPropertyName() {
* @return The new value for the property, expressed as an Object.
* May be null if multiple properties have changed.
*/
public Object getNewValue() {
public @Nullable Object getNewValue() {
return newValue;
}

Expand All @@ -99,7 +103,7 @@ public Object getNewValue() {
* @return The old value for the property, expressed as an Object.
* May be null if multiple properties have changed.
*/
public Object getOldValue() {
public @Nullable Object getOldValue() {
return oldValue;
}

Expand All @@ -108,7 +112,7 @@ public Object getOldValue() {
*
* @param propagationId The propagationId object for the event.
*/
public void setPropagationId(Object propagationId) {
public void setPropagationId(@Nullable Object propagationId) {
this.propagationId = propagationId;
}

Expand All @@ -122,37 +126,37 @@ public void setPropagationId(Object propagationId) {
* @return the propagationId object associated with a bound/constrained
* property update.
*/
public Object getPropagationId() {
public @Nullable Object getPropagationId() {
return propagationId;
}

/**
* name of the property that changed. May be null, if not known.
* @serial
*/
private String propertyName;
private @Nullable String propertyName;

/**
* New value for property. May be null if not known.
* @serial
*/
@SuppressWarnings("serial") // Not statically typed as Serializable
private Object newValue;
private @Nullable Object newValue;

/**
* Previous value for property. May be null if not known.
* @serial
*/
@SuppressWarnings("serial") // Not statically typed as Serializable
private Object oldValue;
private @Nullable Object oldValue;

/**
* Propagation ID. May be null.
* @serial
* @see #getPropagationId
*/
@SuppressWarnings("serial") // Not statically typed as Serializable
private Object propagationId;
private @Nullable Object propagationId;

/**
* Returns a string representation of the object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ public void addPropertyChangeListener(
* returned.
* @since 1.4
*/
@PolyUIEffect public @PolyUI PropertyChangeListener[] getPropertyChangeListeners(@PolyUI PropertyChangeSupport this, String propertyName) {
@PolyUIEffect public @PolyUI PropertyChangeListener[] getPropertyChangeListeners(@PolyUI PropertyChangeSupport this, @Nullable String propertyName) {
return this.map.getListeners(propertyName);
}

Expand All @@ -283,7 +283,7 @@ public void addPropertyChangeListener(
* @param oldValue the old value of the property
* @param newValue the new value of the property
*/
@PolyUIEffect public void firePropertyChange(@PolyUI PropertyChangeSupport this, String propertyName, @Nullable @FenumTop Object oldValue, @Nullable @FenumTop Object newValue) {
@PolyUIEffect public void firePropertyChange(@PolyUI PropertyChangeSupport this, @Nullable String propertyName, @Nullable @FenumTop Object oldValue, @Nullable @FenumTop Object newValue) {
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
}
Expand All @@ -304,7 +304,7 @@ public void addPropertyChangeListener(
* @param newValue the new value of the property
* @since 1.2
*/
@PolyUIEffect public void firePropertyChange(@PolyUI PropertyChangeSupport this, String propertyName, @FenumTop int oldValue, @FenumTop int newValue) {
@PolyUIEffect public void firePropertyChange(@PolyUI PropertyChangeSupport this, @Nullable String propertyName, @FenumTop int oldValue, @FenumTop int newValue) {
if (oldValue != newValue) {
firePropertyChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue));
}
Expand All @@ -325,7 +325,7 @@ public void addPropertyChangeListener(
* @param newValue the new value of the property
* @since 1.2
*/
@PolyUIEffect public void firePropertyChange(@PolyUI PropertyChangeSupport this, String propertyName, boolean oldValue, boolean newValue) {
@PolyUIEffect public void firePropertyChange(@PolyUI PropertyChangeSupport this, @Nullable String propertyName, boolean oldValue, boolean newValue) {
if (oldValue != newValue) {
firePropertyChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
package java.beans;

import org.checkerframework.checker.interning.qual.UsesObjectEquals;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.qual.AnnotatedFor;

import java.io.IOException;
Expand Down Expand Up @@ -84,7 +85,7 @@
* @see PropertyChangeSupport
* @since 1.1
*/
@AnnotatedFor({"interning"})
@AnnotatedFor({"interning", "nullness"})
public @UsesObjectEquals class VetoableChangeSupport implements Serializable {
private VetoableChangeListenerMap map = new VetoableChangeListenerMap();

Expand All @@ -110,7 +111,7 @@ public VetoableChangeSupport(Object sourceBean) {
*
* @param listener The VetoableChangeListener to be added
*/
public void addVetoableChangeListener(VetoableChangeListener listener) {
public void addVetoableChangeListener(@Nullable VetoableChangeListener listener) {
if (listener == null) {
return;
}
Expand All @@ -136,7 +137,7 @@ public void addVetoableChangeListener(VetoableChangeListener listener) {
*
* @param listener The VetoableChangeListener to be removed
*/
public void removeVetoableChangeListener(VetoableChangeListener listener) {
public void removeVetoableChangeListener(@Nullable VetoableChangeListener listener) {
if (listener == null) {
return;
}
Expand Down Expand Up @@ -201,8 +202,8 @@ public VetoableChangeListener[] getVetoableChangeListeners(){
* @since 1.2
*/
public void addVetoableChangeListener(
String propertyName,
VetoableChangeListener listener) {
@Nullable String propertyName,
@Nullable VetoableChangeListener listener) {
if (listener == null || propertyName == null) {
return;
}
Expand All @@ -227,8 +228,8 @@ public void addVetoableChangeListener(
* @since 1.2
*/
public void removeVetoableChangeListener(
String propertyName,
VetoableChangeListener listener) {
@Nullable String propertyName,
@Nullable VetoableChangeListener listener) {
if (listener == null || propertyName == null) {
return;
}
Expand All @@ -249,7 +250,7 @@ public void removeVetoableChangeListener(
* returned.
* @since 1.4
*/
public VetoableChangeListener[] getVetoableChangeListeners(String propertyName) {
public VetoableChangeListener[] getVetoableChangeListeners(@Nullable String propertyName) {
return this.map.getListeners(propertyName);
}

Expand All @@ -274,7 +275,7 @@ public VetoableChangeListener[] getVetoableChangeListeners(String propertyName)
* @param newValue the new value of the property
* @throws PropertyVetoException if one of listeners vetoes the property update
*/
public void fireVetoableChange(String propertyName, Object oldValue, Object newValue)
public void fireVetoableChange(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue)
throws PropertyVetoException {
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
fireVetoableChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
Expand Down Expand Up @@ -303,7 +304,7 @@ public void fireVetoableChange(String propertyName, Object oldValue, Object newV
* @throws PropertyVetoException if one of listeners vetoes the property update
* @since 1.2
*/
public void fireVetoableChange(String propertyName, int oldValue, int newValue)
public void fireVetoableChange(@Nullable String propertyName, int oldValue, int newValue)
throws PropertyVetoException {
if (oldValue != newValue) {
fireVetoableChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue));
Expand Down Expand Up @@ -332,7 +333,7 @@ public void fireVetoableChange(String propertyName, int oldValue, int newValue)
* @throws PropertyVetoException if one of listeners vetoes the property update
* @since 1.2
*/
public void fireVetoableChange(String propertyName, boolean oldValue, boolean newValue)
public void fireVetoableChange(@Nullable String propertyName, boolean oldValue, boolean newValue)
throws PropertyVetoException {
if (oldValue != newValue) {
fireVetoableChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
Expand Down Expand Up @@ -413,7 +414,7 @@ else if (named == null) {
* @return true if there are one or more listeners for the given property
* @since 1.2
*/
public boolean hasListeners(String propertyName) {
public boolean hasListeners(@Nullable String propertyName) {
return this.map.hasListeners(propertyName);
}

Expand Down