I am currently working with PropertyChangeListeners and I want to know if it would be advisable to fire a property change whenever an object is added (or removed, for that matter) to an indexed property such as an ArrayList.
public class SimpleBean implements Serializable
{
private ArrayList<Matrix> mats;
private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public SimpleBean()
{...}
public void addMat(Matrix m)
{
pcs.firePropertyChange("mats", null, m); // I'm having trouble with the parameters
mats.add(m);
}
}
I was reading the PropertyChangeListener tutorials and it seemed like it was appropriate to fire a property change whenever the value of a bound property changed. Well, I wasn't quite sure if this meant that I should fire a property change whenever a property was modified by any means or only when the property (or an element of that property) was strictly set/reassigned to a different value.
In my program, it would be very convenient if several classes could change every time an element is removed from or added to the mats ArrayList, and I figured that a PropertyChangeListener could help me in that regard.
Please let me know if this method is not recommended and if there is another way that other classes can listen and respond to deletion/addition to indexed properties.
See the following example:
public class SimpleBean implements Serializable {
private ArrayList<Matrix> mats;
private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public void setMats(ArrayList<Matrix> mats) {
if(mats.equals(this.mats))
return;
ArrayList<Matrix> oldMats = this.mats ;
this.mats = mats ;
pcs.firePropertyChange("mats", oldMats, mats);
}
public ArrayList<Matrix> getMats() {
return mats;
}
public void setMat(int index, Matrix mat) {
Matrix existing = index == mats.size() ? null : mats.get(index);
if(existing.equals(mat))
return;
mats.remove(index);
mats.add(index, mat);
pcs.fireIndexedPropertyChange("mats", index, existing, mat);
}
public Matrix getMat(int index) {
return mats.get(index);
}
public void addMat(Matrix m) {
setMat(mats.size(), m);
}
}
Which implements both propertyChange as well as indexedPropertyChange for mats.
Related
How can i create a method that accepts Class and Field as parameters? Like this:
List<SomeClassEntity> list = ...;
// Service to make useful things around a list of objects
UsefulThingsService<SomeClassEntity> usefulThingsService = new UsefulThingsService<>();
// Maybe invoke like this. Did't work
usefulThingsService.makeUsefulThings(list, SomeClassEntity.class, SomeClassEntity::getFieldOne);
// or like this. Will cause delayed runtime erros
usefulThingsService.makeUsefulThings(list, SomeClassEntity.class, "fieldTwo");
public class SomeClassEntity {
Integer fieldOne = 10;
Double fieldThree = 0.123;
public Integer getFieldOne() {
return fieldOne;
}
public void setFieldOne(Integer fieldOne) {
this.fieldOne = fieldOne;
}
public Double getFieldThree() {
return fieldThree;
}
public void setFieldThree(Double fieldThree) {
this.fieldThree = fieldThree;
}
}
public class UsefulThingsService<T> {
public void makeUsefulThings(Class<T> someClassBClass, String fieldName) {
// there is some code
}
}
Want to have correct references on compile stage, not at runtime.
Update:
I need code that would look more convenient than this:
Field fieldOne = null;
try {
fieldOne = SomeClassEntity.class.getDeclaredField("fieldOne");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
usefulThingsService.makeUsefulThings(SomeClassEntity.class, fieldOne);
I apologize for the next clarification.
Update 2:
- The service compares the list with the previous list, reveals only the changed fields of objects (list items) and updates these fields in the objects in the original list.
- Currently i use annotation on entity's field that is actually ID of the entity and that ID is used to detect identically entities (old and new) when i need to update field of entity in source list.
- Service detect annotated field and use it for next update process.
- I want to refuse to use annotations and provide an Field directly in constructor of service. Or use something other that could establish a relationship between class and field on compilation stage.
Assuming that you want field access because you want to get and set the value, you’d need two functions:
public class UsefulThingsService<T> {
public <V> void makeUsefulThings(List<T> list, Function<T,V> get, BiConsumer<T,V> set) {
for(T object: list) {
V v = get.apply(object);
// there is some code
set.accept(object, v);
}
}
}
and
usefulThingsService.makeUsefulThings(
list, SomeClassEntity::getFieldOne, SomeClassEntity::setFieldOne);
usefulThingsService.makeUsefulThings(
list, SomeClassEntity::getFieldThree, SomeClassEntity::setFieldThree);
There are, however, some things open. E.g., how is this service supposed to do something useful with the field resp. property, without even knowing its actual type. In your example, both are subtypes of Number, so you could declare <V extends Number>, so the method knows how to extract numerical values, however, constructing an appropriate result object would require specifying another function argument.
I am studying ReadOnlyStringWrapper.ReadOnlyPropertyImpl class of JavaFX11 that is:
private class ReadOnlyPropertyImpl extends ReadOnlyStringPropertyBase {
#Override
public String get() {
return ReadOnlyStringWrapper.this.get();
}
#Override
public Object getBean() {
return ReadOnlyStringWrapper.this.getBean();
}
#Override
public String getName() {
return ReadOnlyStringWrapper.this.getName();
}
};
The instance of ReadOnlyPropertyImpl is returned to client that can work with it in read only mode. The thing I can't understand is where ReadOnlyPropertyImpl will take the oldValue for ChangeListener. As we see it overrides only get method for current value, that is taken from the wrapper. Could anyone explain?
The current value is stored in the helper class that is used for the event handling, see com.sun.javafx.binding.ExpressionHelper. E.g. if you take a look at the concrete implementation in the SingleChange static inner class:
private T currentValue;
...
#Override
protected void fireValueChangedEvent() {
final T oldValue = currentValue;
currentValue = observable.getValue();
...
listener.changed(observable, oldValue, currentValue);
...
}
Generic, the other class for handling change events has a similar implementation.
Adding listeners results in the creation of a ExpressionHelper instance (or the modification of a existing one) and this this object is responsible for invoking event handlers. (The ExpressionHandler is stored in a field of the property object, in this case in ReadOnlyStringPropertyBase's helper field.)
In my understanding of Java, the most common ways to set the instance variables of a class object are:
foo.setFooStuff(bar); // put a setter method inside the class
foo = modifyFooStuff(foo, bar); // pass & return entire object
Let's say my main() has an object of class bigA, which contains a collection of class littleA objects (which contain instance variables), and another object of class bigB, which contains a collection of class littleB objects (which have different instance variables from littleA). How do I write a method to modify instance variables of one or more littleA and littleB objects at the same time?
(Note: I suspect this is a common question, but I searched and didn't find it. Maybe I'm using the wrong terminology.)
Edit: more concrete example: Let's say I'm making Monopoly. A player has money (in various denominations) and properties (some with houses). She wants to upgrade some properties to hotels. Money has to be added and subtracted, as do houses and hotels. I know how to do this in a pass-by-reference language, but not using pass-by-value, unless I make the entire game state into one huge object and pass it around, which seems like a lot of memory shuffling and basically the same as using global variables, which is bad, right?
If I understand your question correctly, you write a method on the bigA/bigB classes that take the value you want to set and then walk the collection of littleA/B objects setting the instance variables as you go. Like:
// Assuming Foo has a member collection of smallFoo
Foo A = new Foo();
// do stuff that populates the collection of smallFoo in A
A.setSmallFooZipCode("23444");
public void setSmallFooZipCode(String zip_ {
// for thisSmallFoo in smallFoo
thisSmallFoo.setZip(zip);
// end for
)
Objects (including your container objects) should represent something--thinking of them in terms of A/B makes this a little tough.
On top of that, if you are always modifying an attribute in two classes at once I'd suggest that's a pretty bad code smell...
Off the top of my head I can't think of anything I'd model this way, so it's hard to come up with an example. Either A and B should be contained in a parent ab class (and that class should have the attribute), or a and b should be the same interface--in either case these would then go into a single collection in a parent container.
So that said, you should have a method on the parent container object that does the work. In most cases it shouldn't be a method like "setAttribute...", it should be a method like "doAction". In other words, if your container is a "Herd" and it contains a bunch of Elephants, then you would tell the Herd to move to a certain location and let the Herd object send a message to each elephant telling it where to go.
If you think of methods in terms of "Asking an object to do something for you" rather than operating on an object, it helps make some of these decisions much easier.
You would simply encapsulate BigA and BigB in another object:
class BigWrapper {
private BigA bigA;
private BigB bigB;
public void someMethod() {
bigA.someMethod();
bigB.someMethod();
}
}
someMethod() within BigA would modify the LittleA instances. Same for BigB:
class BigB {
private LittleA[] littles;
public void someMethod() {
//do something with the littles
}
}
Of course, this solution doesn't allow you to specify which Little instances to target, as well as doesn't allow you to specify which behavior should be performed (which specific method to invoke via the littles).
If you want that flexibility, use callbacks:
interface Little { }
class LittleA implements Little { }
class LittleB implements Little { }
interface Callback<T extends Little> {
void perform(int currentIndex, T currentLittle);
}
class CallbackHandler<T extends Little> {
private int[] indexes;
private Callback<T> callback;
public CallbackHandler(int[] indexes, Callback<T> callback) {
this.indexes = indexes;
this.callback = callback;
}
public void perform(T[] littles) {
for(int i = 0; i < indexes.length; i++) {
int index = indexes[i];
callback.perform(i, littles[index]);
}
}
}
class BigWrapper {
private BigA bigA;
private BigB bigB;
public BigWrapper(BigA bigA, BigB bigB) {
this.bigA = bigA;
this.bigB = bigB;
}
public void perform(CallbackHandler<LittleA> aCallback, CallbackHandler<LittleB> bCallback) {
bigA.perform(aCallback);
bigB.perform(bCallback);
}
}
class BigA {
private LittleA[] littles;
public BigA(LittleA[] littles) {
this.littles = littles;
}
public void perform(CallbackHandler<LittleA> callback) {
callback.perform(littles);
}
}
class BigB {
private LittleB[] littles;
public BigB(LittleB[] littles) {
this.littles = littles;
}
public void perform(CallbackHandler<LittleB> callback) {
callback.perform(littles);
}
}
The CallbackHandler maps the actual callback to the indexes you want to target.
So you would first create the callback:
Callback<LittleA> aCallback = (currentIndex, currentLittle) -> {
//do what you want to the littles
};
Then pass that to a CallbackHandler, which allows you to specify the indexes you wish to target:
int[] indexes = { 0, 1, 2 };
CallbackHandler<LittleA> aCallbackHandler = new CallbackHandler<>(indexes, aCallback);
BigWrapper exposes a perform(CallbackHandler<LittleA>, CallbackHandler<LittleB>), so you would pass the handlers to that method.
An MCVE would look like:
public static void main(String[] args) {
LittleA[] littleA = {
new LittleA(),
new LittleA(),
new LittleA()
};
LittleB[] littleB = {
new LittleB(),
new LittleB(),
new LittleB()
};
BigA bigA = new BigA(littleA);
BigB bigB = new BigB(littleB);
BigWrapper big = new BigWrapper(bigA, bigB);
Callback<LittleA> aCallback = (index, little) -> {
//...
};
Callback<LittleB> bCallback = (index, little) -> {
//...
};
CallbackHandler aCallbackHandler = new CallbackHandler(new int[] { 2, 3, 4 }, aCallback);
CallbackHandler bCallbackHandler = new CallbackHandler(new int[] { 5, 6, 7 }, bCallback);
big.perform(aCallbackHandler, bCallbackHandler);
}
This class is where I want to call the arrays and set the arrays to empty within the parameters
public class ElectronicsEquipmentSupplier {
private int currentMonth;
private int currentYear;
private String rangeOfProducts;
private CustomerDetailsList details; //Contains the customer details array
private PurchaseOrderList pal; //Contains the purchase array
public ElectronicsEquipmentSupplier(int currentMonth, int currentYear,
String rangeOfProducts ) {
this.currentMonth = currentMonth;
this.currentYear = currentYear;
this.rangeOfProducts = rangeOfProducts;
}
}
This is the class where the array is created. It pulls information from a separate class called PurchaseOrder and then sets the list.
public class PurchaseOrderList {
private ArrayList<PurchaseOrder> purchaseCollection;
public PurchaseOrderList() {
purchaseCollection = new ArrayList<PurchaseOrder>();
}
The CustomerDetailsList class is essentially the same. Just not sure as to the best way to set the array to empty when called in the ElectronicsEquipmentSupplier.
Simply wrap the collection's own clear() method with a publicly-accessible method in your PurchaseOrderClass:
public class PurchaseOrderList {
private ArrayList<PurchaseOrder> purchaseCollection;
public PurchaseOrderList() {
purchaseCollection = new ArrayList<PurchaseOrder>();
}
//THIS IS THE IMPORTANT PART
public void clearPurchaseCollection() {
purchaseCollection.clear();
//You could also accomplish the same thing by reinitializing the list:
//purchaseCollection = new ArrayList<PurchaseOrder>();
}
}
Note however, that calling new PurchaseOrderList() already guarantees an empty purchaseCollection list, since you initialize it in the constructor that way.
So the only time you would need to call clearPurchaseCollection() is if you are reusing this object and want to clean it out first. Depending on the rest of your application, that may be necessary, but it may also just be simpler to throw away that instance and create a new PurchaseOrderList(). Totally depends on the situation.
Given that I have this entity as part of an editor chain:
public class Commission implements Serializable
{
private EnumSet<CommissionType> commissionTypes;
private CommissionType type; // must exist in commissionTypes
private String value;
public Commission()
{
}
}
and this editor for it:
public class CommissionEditor extends Composite implements Editor<Commission>
{
private static CommissionEditorUiBinder uiBinder = GWT.create(CommissionEditorUiBinder.class);
interface CommissionEditorUiBinder extends UiBinder<Widget, CommissionEditor>
{
}
#UiField(provided = true)
ValueListBox<CommissionType> type = new ValueListBox<CommissionType>(new AbstractRenderer<CommissionType>()
{
#Override
public String render(CommissionType object)
{
return object == null ? "" : object.toString();
}
});
#UiField
TextBox value;
public CommissionEditor()
{
type.setAcceptableValues(Arrays.asList(CommissionType.values()));
initWidget(uiBinder.createAndBindUi(this));
}
}
At the moment the ValueListBox renders all possible options for CommissionType, like this:
The EnumSet could contain between 1 and 4 of the possible options, depending on the particular entity. Is there a way to make the ValueListBox only render the options in the EnumSet and then save the value in commissionType?
Bear in mind that I want to set the value of commissionType as well.
There are two ways to solve it:
1.) If you have a direct access to the CommissionEditor then create a setter in it call it when you edit the entity:
public void setAcceptableValues(List<CommissionType> values) {
type.setAcceptableValues(values);
}
And call it like this when you call driver.edit(entity);:
commissionEditor.setAcceptableValues(commission.getCommissionTypes());
2.) Instead of extending the Editor interface you can extend the ValueAwareEditor and in the setValue() method call setAcceptableValues with the corresponding values.
Approach 2 is probably the cleaner approach.