Summary
AbstractCategoryItemLabelGenerator.equals(Object) does not compare percentFormat, but hashCode() includes it. This means two generators with different percent formatters can compare equal while producing different labels. nullValueString has the same situation.
Affected code
File: src/main/java/org/jfree/chart/labels/AbstractCategoryItemLabelGenerator.java
private final NumberFormat percentFormat;
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof AbstractCategoryItemLabelGenerator)) {
return false;
}
AbstractCategoryItemLabelGenerator<R, C> that
= (AbstractCategoryItemLabelGenerator<R, C>) obj;
if (!this.labelFormat.equals(that.labelFormat)) {
return false;
}
if (!Objects.equals(this.dateFormat, that.dateFormat)) {
return false;
}
if (!Objects.equals(this.numberFormat, that.numberFormat)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = 127;
result = HashUtils.hashCode(result, this.labelFormat);
result = HashUtils.hashCode(result, this.nullValueString);
result = HashUtils.hashCode(result, this.dateFormat);
result = HashUtils.hashCode(result, this.numberFormat);
result = HashUtils.hashCode(result, this.percentFormat);
return result;
}
Reproducer
Add the following test to src/test/java/org/jfree/chart/labels/StandardCategoryItemLabelGeneratorTest.java:
@Test
public void testEqualsDifferentPercentFormat() {
StandardCategoryItemLabelGenerator g1
= new StandardCategoryItemLabelGenerator("{2}",
new DecimalFormat("0.000"), new DecimalFormat("0.0%"));
StandardCategoryItemLabelGenerator g2
= new StandardCategoryItemLabelGenerator("{2}",
new DecimalFormat("0.000"), new DecimalFormat("0.00%"));
assertNotEquals(g1, g2);
}
Run:
mvn -q -Dtest=org.jfree.chart.labels.StandardCategoryItemLabelGeneratorTest test
Observed behavior
StandardCategoryItemLabelGeneratorTest.testEqualsDifferentPercentFormat:125
expected: not equal but was: <org.jfree.chart.labels.StandardCategoryItemLabelGenerator@...>
Expected behavior
Objects with different percentFormat values should not compare equal.
Why this is a bug
percentFormat affects the rendered item label text.
equals() ignores it.
hashCode() includes it.
So the current implementation violates both semantic equality and the equals/hashCode contract.
Summary
AbstractCategoryItemLabelGenerator.equals(Object)does not comparepercentFormat, buthashCode()includes it. This means two generators with different percent formatters can compare equal while producing different labels.nullValueStringhas the same situation.Affected code
File:
src/main/java/org/jfree/chart/labels/AbstractCategoryItemLabelGenerator.javaReproducer
Add the following test to
src/test/java/org/jfree/chart/labels/StandardCategoryItemLabelGeneratorTest.java:Run:
mvn -q -Dtest=org.jfree.chart.labels.StandardCategoryItemLabelGeneratorTest testObserved behavior
Expected behavior
Objects with different
percentFormatvalues should not compare equal.Why this is a bug
percentFormataffects the rendered item label text.equals()ignores it.hashCode()includes it.So the current implementation violates both semantic equality and the
equals/hashCodecontract.