views:

191

answers:

2

I'll try to explain my problem as clear as possible :). I am using PropertyChangeSupport to notify registered views for changes in the properties. One of the property is an object which properties are changed every view seconds. I don't want to create for this particular object new instance every time it is being updated (for the propertychangelistener to notice the change), so I wrote my own equals method where I ommit the comparation to itself.

@Override
public boolean equals(Object item) {
 // do not compare 
 // if (this == item) { return true; }

 if (!(item instanceof TransferQueueItem) || 
  item == null) {

  return false;
 }

 TransferQueueItem newItem = (TransferQueueItem) item;
 boolean value = 
   // ommited... properties comparation
 return value;
}

Unfortunatelly that doesn't have the effect I was looking for. If I create a copy of the object and fire the property change method on it, then it works fine.

What am I missing here?

-- Edit

I realized, that since I am using the same instance and not a copy of it, the properties are pointig the same place, thus the comparation would always come out true. Is there a workaround to that (besides creating a copy). Or how bad is to create a copy of an object every second, eg.

+1  A: 

You must always return true to tell PropertyChangeSupport that your object did not change. But that means equals() is broken for all objects of this class (so you can't use them in sets or maps anymore, for example).

A better way would be to have a special method firePropertyChange() for this kind of object which does the special handling. This way, you can even avoid to create an instance of PropertyChangeEvent, too. Here is an example for handling BigDecimal (where equals() doesn't work at all):

protected transient PropertyChangeSupport changeSupport = null;

public void addPropertyChangeListener (String propertyName, PropertyChangeListener listener)
{
    if (changeSupport == null)
        changeSupport = new PropertyChangeSupport (this);

    changeSupport.addPropertyChangeListener (propertyName, listener);
}

public void firePropertyChange (String propertyName, BigDecimal oldValue, BigDecimal newValue)
{
    if (changeSupport == null)
        return;

    if (oldValue != null && newValue != null && oldValue.compareTo (newValue) == 0) {
        return;
    }
    changeSupport.firePropertyChange(new PropertyChangeEvent(this, propertyName,
                                               oldValue, newValue));
}

[EDIT] What you do is something else entirely: You have a parent and a child and you want listeners of the parent to receive events when the child changes.

The correct approach here is to add PropertyChangeSupport to the child. When the child is added to the parent, the parent must install the necessary listeners in the child. When an event is fired, it must fire a second event which informs the listeners of the parent of the change in the child (the parent must forward the events).

Aaron Digulla
Actually I want the opposite of that. And to always return hard-coded value is not exactly what equals should be about.
stefita
In that case, your question is unclear. Do you want to avoid firing events for any change to the TransferQueueItem? Do you always want an event when TransferQueueItem changes? Do you always want an event when a property of TransferQueueItem changes?
Aaron Digulla
Note that it's a difference whether you set a new TransferQueueItem or when you change properties of TransferQueueItem.
Aaron Digulla
I whant an event every time TransferQueueItem changes, but TransferQueueItem is just a property of TransferQueue, so it isn't the one firing the events.
stefita
Thanks, I will try that.
stefita
The listeners add themselves to the TransferQueue Object, which is also the one firing the propertychange events.
stefita
Who fires the events and where do listeners add themselves to?
Aaron Digulla
Ahhh ... here we go. See my edits.
Aaron Digulla
Thank you for the hints. They truly pointed me to the right direction. It wasn't clear to me at the begining how to notify the parent object of changes in the child, but I got it now. Thanks again!
stefita
+1  A: 

this is a case of chained propertychangelisteners:

TransferQueueItem should launch their own PropertychangeEvents which must be listened by the TransferQueue in which is inserted

And in response TransferQueue must notify their listeners that an owned item has changed.

Every time i have a problem like this in which an object must relaunch events i use this convention (of my work team):

1 An object can only launch events which source is itself.

2 If it want delegate event it launchs an event like this: new PropertyChangeEvent(this,"DELEGATED_EVENT", null, receivedEvent). So that the listeners can follow the chain of events.

Addicionally i have a static method in an Util class which follow the events chain and returns the very first event, the one whick property is not "DELEGATED_EVENT"

Telcontar
Thanks for the pointers! It does make sense to implement it that way.
stefita