Home > Net >  Creating an object binding of a list of BigDecimals to get a total
Creating an object binding of a list of BigDecimals to get a total

Time:06-24

I'm trying to create a binding of a list of LineItem's amounts with the following line:

ReadOnlyObjectWrapper<BigDecimal> total = new ReadOnlyObjectWrapper<>();

total.bind(Bindings.createObjectBinding(() -> items.stream()
                        .collect(Collectors.summingDouble(LineItem::getTotal)),
                        items));

Obviously, the Collectors.summingDouble won't work as it's a BigDecimal. Is there any way to do this with a BigDecimal?

LineItem.java

public class LineItem
{
        private final SimpleObjectProperty<BigDecimal> amount;
        
        public LineItem()
        {
            this.amount = new SimpleObjectProperty<>();
        }
        
        public BigDecimal getTotal()
        {
            return this.amount.get();
        }
        
}
    

Ideally, changes to the properties will reflect in the total property...

CodePudding user response:

There are a few changes to make to make this work:

  1. You need to define a "property accessor" method in your LineItem class, to access the actual ObjectProperty<BigDecimal> (not just the BigDecimal it wraps). This allows the list to send notifications if the individual amounts change.
  2. You need to create your ObservableList with an "extractor", so it can send update notifications to your binding, if the individual amount properties change
  3. Fix the function in the binding to sum the BigDecimal instances, as described in this question

This looks like:

public class LineItem {
    private final SimpleObjectProperty<BigDecimal> amount;
    
    public LineItem()
    {
        this.amount = new SimpleObjectProperty<>();
    }
    
    public final BigDecimal getTotal()
    {
        return this.amount.get();
    }

    public ObjectProperty<BigDecimal> totalProperty() {
        return amount ;
    }

    public final void setTotal(BigDecimal total) {
        totalProperty().set(total);
    }
    
}

then

ObservableList<LineItem> items = FXCollections.observableArrayList(
    item -> new Observable[] {item.totalProperty()}
);

and

total.bind(Bindings.createObjectBinding(() -> items.stream()
         .map(LineItem::getTotal)
         .reduce(BigDecimal.ZERO, BigDecimal::add),
     items));
  • Related