Java PropertyChangeListener detects property changes

1.First of all

This time, I would like to explain how to detect that a property has been changed by using the standard Java API PropertyChangeListener.

The process of detecting events is well known in Java GUI applications such as SWT, Swing, and AWT, but even ordinary Java classes have a mechanism to detect events whose properties have changed.

2. Implementation

2.1. Classes to be checked

Item.java


package com.example.demo;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class Item {

    private int price;

    //★ Point 1
    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

    //★ Point 2
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.addPropertyChangeListener(listener);
    }

    //★ Point 3
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.removePropertyChangeListener(listener);
    }

    public int getPrice() {
        return price;
    }

    //★ Point 4
    public void setPrice(int price) {
        int oldPrice = this.price;
        this.price = price;
        this.pcs.firePropertyChange("price", oldPrice, price);
    }

    // generated by eclipse
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Item [price=");
        builder.append(price);
        builder.append("]");
        return builder.toString();
    }
}

** ★ Point 1 ** Create an instance of java.beans.PropertyChangeSupport and define it as a field. The constructor argument of PropertyChangeSupport specifies this because it is the object that originated (detected) the event.

** ★ Point 2 ** Implement the method to add java.beans.PropertyChangeListener to PropertyChangeSupport defined in ★ Point 1.

** ★ Point 3 ** Implement a method that removes java.beans.PropertyChangeListener from PropertyChangeSupport. Please think that ★ Point 2 and ★ Point 3 are the usual things to implement as a set.

** ★ Point 4 ** Raise a property change event with the firePropertyChange method of PropertyChangeSupport.

Person.java


package com.example.demo;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class Person {

    private String name;

    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.removePropertyChangeListener(listener);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        String oldName = this.name;
        this.name = name;
        this.pcs.firePropertyChange("name", oldName, name);
    }

    // generated by eclipse
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Person [name=");
        builder.append(name);
        builder.append("]");
        return builder.toString();
    }
}

2.2. Class that detects changes

DemoListener.java


package com.example.demo;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

//★ Point 5
public class DemoListener implements PropertyChangeListener {

    //★ Point 6
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        //★ Point 7
        Object eventTriggerObject = evt.getSource();
        String propertyName = evt.getPropertyName();

        //★ Point 8
        if (Item.class.isInstance(eventTriggerObject)) {
            if ("price".equals(propertyName)) {
                //★ Point 9
                Integer oldValue = (Integer) evt.getOldValue();
                Integer newValue = (Integer) evt.getNewValue();
                System.out.println("[Item.price] oldValue:" + oldValue + " -> newValue:" + newValue);
            }
        } else if (Person.class.isInstance(eventTriggerObject)) {
            if ("name".equals(propertyName)) {
                String oldValue = (String) evt.getOldValue();
                String newValue = (String) evt.getNewValue();
                System.out.println("[Person.name] oldValue:" + oldValue + " -> newValue:" + newValue);
            }
        }
    }
}

** ★ Point 5 ** Defines a class that implements the java.beans.PropertyChangeListener interface.

** ★ Point 6 ** Implement the process of handling property change events by overriding the propertyChange method.

** ★ Point 7 ** Get the object from which the change event originated with the getSource () method of java.beans.PropertyChangeEvent. Also, the changed property can be specified by using the getPropertyName () method because the property name can be obtained.

** ★ Point 8 ** This time, listeners are registered in both the ʻItem class and the Person` class, so it is necessary to determine which instance is the source.

** ★ Point 9 ** The value before the property change is obtained by the getOldValue () method, and the value after the change is obtained by the getNewValue () method. The return value is ʻObject`, so you need to cast it according to the data type of the property.

2.3. Operation check demo app class

App.java


package com.example.demo;

public class App {

    public static void main(String[] args) {
        Item item = new Item();
        System.out.println(item);
        item.setPrice(500);
        System.out.println(item);

        DemoListener demoListener = new DemoListener();
        item.addPropertyChangeListener(demoListener);

        item.setPrice(700);
        item.setPrice(1000);

        Person person = new Person();
        System.out.println(person);
        person.setName("Taro");
        System.out.println(person);

        person.addPropertyChangeListener(demoListener);
        person.setName("5zm");
        person.setName("Yamada");

        item.removePropertyChangeListener(demoListener);
        person.removePropertyChangeListener(demoListener);
    }
}

3. Execution result

Item [price=0]
Item [price=500]
[Item.price] oldValue:500 -> newValue:700
[Item.price] oldValue:700 -> newValue:1000
Person [name=null]
Person [name=Taro]
[Person.name] oldValue:Taro -> newValue:5zm
[Person.name] oldValue:5zm -> newValue:Yamada

Before adding a listener with ʻaddPropertyChangeListener, setting a value with setter` does nothing, and after adding a listener, you can see that the changed content is detected by the listener.

4. Finally

This time, I explained how to detect that a property has been changed by using the standard Java API PropertyChangeListener. By using PropertyChangeListener, you can easily try event processing without preparing a special library.

Recommended Posts

Java PropertyChangeListener detects property changes
Changes in Java 11
Changes from Java 8 to Java 11
Java version notation that changes in Java 10