Immuatable Object with "normalized" BigDecimal field. #987
Replies: 9 comments
-
The answer is in the first line of the page you linked:
In other words: var a = new BigDecimal("1");
var b = new BigDecimal("1.0");
a.equals(b); // returns false!
a.compareTo(b) == 0 // returns true Because of this strange behavior, the general advice is to use So, if you intended |
Beta Was this translation helpful? Give feedback.
-
Either my english is very bad (which is totally possible 😅) OR maybe you read me too fast 🤷 . I'm aware of what you explain here, please read my comment again. 🙏 In your documentation, you talk about 3 solution :
I'm talking about solution 3. |
Beta Was this translation helpful? Give feedback.
-
I totally misunderstood you the first time, sorry about that! You're completely right, EqualsVerifier still wants you to suppress the warning, if you normalize the bigdecimals when they come in. I guess I never properly tested that scenario when I wrote the docs... Unfortunately, there's little I can do about it. EqualsVerifier has no way of seeing that you normalized the BigDecimal, so the suppression is still necessary. I will update the error message and the documentation to make this more clear. |
Beta Was this translation helpful? Give feedback.
-
For immutable class, I have in mind that that EqualsVerifier could create instance using constructors then test for equals ? @Test
public void manualTest() {
BigDecimal referenceField = new BigDecimal("1.12322");
// same number with different scale
BigDecimal changedField = referenceField.setScale(referenceField.scale() + 1, RoundingMode.UNNECESSARY);
ClassWithBigDecimalField referenceInstance = new ClassWithBigDecimalField(referenceField);
ClassWithBigDecimalField changedInstance = new ClassWithBigDecimalField(changedField);
// check equals and hashcode :this is OK ✅
assertEquals(referenceInstance, changedInstance);
assertEquals(referenceInstance.hashCode(), changedInstance.hashCode());
} Do you think this could be something doable ? |
Beta Was this translation helpful? Give feedback.
-
Unfortunately EqualsVerifier doesn't work that way, and it would require major re-architecting to make it do that. Calling constructors is hard and dangerous; they can throw exceptions in unexpected ways, and they might not initialize all the fields in predictable ways. (I have some plans in that direction, but it's hard to find the time to work on them.) But yeah, if it did call the constructor, I could possibly make that work... |
Beta Was this translation helpful? Give feedback.
-
True. I would never have thought that writting and testing
I'm curious to know how you plan to deal with exception ? Do you have some documentation about that ? or some thought to share ? Maybe catching |
Beta Was this translation helpful? Give feedback.
-
I just find : https://jqno.nl/equalsverifier/manual/relaxed-equality/ @Test
public void testEquality() {
ClassWithBigDecimalField a = new ClassWithBigDecimalField(new BigDecimal("1.0"));
ClassWithBigDecimalField b = new ClassWithBigDecimalField(new BigDecimal("1"));
ClassWithBigDecimalField c = new ClassWithBigDecimalField(new BigDecimal("1.00"));
ClassWithBigDecimalField x = new ClassWithBigDecimalField(new BigDecimal("1.01"));
EqualsVerifier.forRelaxedEqualExamples(a, b, c).andUnequalExample(x).verify();
} but it failed with :
This is expected because my constructor create 2 identical instances and the doc clearly says :
But maybe it make sense to have this kind of API also for use case like this one ? 🤔 |
Beta Was this translation helpful? Give feedback.
-
The plan for the constructor thing, was to make it possible for the user to choose between the reflection, or to let them provide a factory of some kind. The plans don't have a lot of detail yet :) It's a bit early to discuss them, especially since I don't know if I'll ever get to them. The idea behind the relaxed equality is to allow classes like fractions: |
Beta Was this translation helpful? Give feedback.
-
Let me know when your work on it, I'm curious.
👍 Thx again for your time 🙏 |
Beta Was this translation helpful? Give feedback.
-
Reading BigDecimal equality, I understand that one possible way to solve
equals
/hashcode
issue withBigDecimal
fields is to normalized field at object constructor of immutable class.This ☝️ makes sense to me but I didn't understand why the library complains when we do that with something like :
I totally understand that for now I need to suppress : Warning.BIGDECIMAL_EQUALITY to disable this check.
But as my code behave correctly, equalsVerifier should be able to test it ?
Here a code example :
The class to test :
Some tests :
So why equalsVerifier library does not generate a test like the manual one above ?
Maybe because of some Java Reflection Limitation ?
Beta Was this translation helpful? Give feedback.
All reactions