0

I can't understand why it's happening on a compareTo method using CompareToBuilder from Apache Commons Lang 3 and how may I solve it?

The class is as follow:

import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.CompareToBuilder;

@Data
@EqualsAndHashCode(of = {"segno", "causale", "importi"})
public class SaraReportAggregate implements Comparable<SaraReportAggregate> {

    private final String segno;
    private final String causale;
    private final AggregatoSara importi = new AggregatoSara();

    @Data
    public static class AggregatoSara implements Comparable<AggregatoSara> {

        private long importoTotale;
        private long importoTotaleContanti;
        private long numeroTotaleOperazioni;
        private long numeroTotaleOperazioniContanti;
    
        @Override
        public int compareTo(AggregatoSara other) {
            return new CompareToBuilder()
                    .append(other.importoTotale, this.importoTotale)
                    .append(other.numeroTotaleOperazioni, this.numeroTotaleOperazioni)
                    .append(other.importoTotaleContanti, this.importoTotaleContanti)
                    .append(other.numeroTotaleOperazioniContanti, this.numeroTotaleOperazioniContanti)
                    .toComparison();
        }
    }

    @Override
    public int compareTo(SaraReportAggregate other) {
        return new CompareToBuilder()
                .append(this.importi, other.importi)
                .append(this.causale, other.causale)
                .append(this.segno, other.segno)
                .toComparison();
    }
}

Calling Collections#sort(List) on a list of SaraReportAggregate happened to throw

java.lang.IllegalArgumentException: Comparison method violates its general contract!

What should I do?

letsintegreat
  • 3,328
  • 4
  • 18
  • 39
noiaverbale
  • 1,550
  • 13
  • 27
  • @WJS if you look closely he has 2 Strings and 4 longs, and internally `CompareToBuilder` does the correct thing - I checked. This is weird. – Eugene Jan 29 '21 at 15:11
  • You didn't override `equals()` on these classes, so probably the contract that's being broken is that `compareTo` and `equals` are not returning consistent results. – Kevin Anderson Jan 29 '21 at 15:16
  • @KevinAnderson why would `equals` (and `hashCode`) matter then you are _comparing_ elements, though? – Eugene Jan 29 '21 at 15:18
  • It wouldn't, **if you could guarantee that whatever was doing the comparing relied only on `compareTo`**. How often do you have the luxury of being able to make that guarantee? – Kevin Anderson Jan 29 '21 at 15:22
  • @KevinAnderson by the way, hash and equals are implemented by Lombok's `EqualsAndHashCode` – noiaverbale Jan 29 '21 at 15:30
  • but the order is not correct, and the documentation of `ComparisonBuilder` requires it: _The same fields, **in the same order**, should be used in both compareTo(Object) and equals(Object)_ – Eugene Jan 29 '21 at 15:32
  • The CompareToBuilder-based `compareTo` of `SaraReportAggregate` explicily includes a deep compare of the `importi` fields. Are you certain the Lombok-based `equals` is also deep-comparing `importi'? – Kevin Anderson Jan 29 '21 at 16:05

0 Answers0