2

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...

trilogy
  • 1,738
  • 15
  • 31
  • 2
    Voted to reopen. This question is about creating a JavaFX binding, that is not what the [previously linked duplicate](https://stackoverflow.com/questions/22635945/adding-up-bigdecimals-using-streams) documented. – jewelsea Jun 23 '22 at 16:52
  • 1
    Is the list of `LineItem` an [ObservableLIst](https://docs.oracle.com/javase/8/javafx/api/javafx/collections/ObservableList.html) ? – Abra Jun 23 '22 at 17:03
  • @Abra yes it is – trilogy Jun 23 '22 at 17:11

1 Answers1

5

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));
James_D
  • 201,275
  • 16
  • 291
  • 322