Is it possible using compareTo rather than equals to compare BigDecimal ?
Now, I have to create a specific method equals for BigDecimal objects and add all of them in exclude of @EqualsAndHashCode.
I found some discussion about that problem :
http://stackoverflow.com/questions/36625347/how-to-make-lomboks-equalsandhashcode-work-with-bigdecimal
http://tech.transferwise.com/fun-with-bigdecimal/
https://groups.google.com/forum/#!searchin/project-lombok/BigDecimal|sort:relevance/project-lombok/oRdyHiecgWE/GHLLhL8FYdIJ
Maybe just an option in annotation @EqualsAndHashCode for switching between equals and compareTo for some kind of classes...
Unfortunately, this is not possible. Also, if you put them in an array or collection, that also wouldn't work.
We are looking into a system to provide method for specific fields, but we're not there yet.
Oh, by the way, beware that if the equals returns true, the hashCodes should also be the same. How would you do that?
We are looking into a system to provide method for specific fields, but we're not there yet.
AFAIK the problem is lacking a suitable interface in rt.jar. The problem could be solved the other way round: Use something else in place of a field value (think writeReplace or readResolve). Annotating a field like @EqHC(use=someMethod) isn't refactoring-friendly (), but we don't have to specify that "someMethod" gets used exactly *instead of "someField". Just exclude "someField" and include "someMethod" like in
@EqualsAndHashCode
class MyClass {
@EqualsAndHashCode.Exclude
private BigDecimal myDecimal;
@EqualsAndHashCode.Include
private Object myDecimalForEqHC() {
return myDecimal.stripTrailingZeros();
}
}
It's a bit verbose, but still much shorter and cleaner than writing your own. It also solves #1223 and this idea could be used as a workaround for #1262 and other issues where a single field prevents using Lombok for the whole class. Just allow no-args methods to be used as if they were fields.
Oh, by the way, beware that if the equals returns true, the hashCodes should also be the same. How would you do that?
The OP's idea of using compareTo don't seem to work together with hashCode, but using equals/hashCode on a no-arg method's result is fine.
(*) I'm assuming you want to deprecate of and exclude some day.
I don't think this issue should be closed.
It would be great to be able to provide a specific equals method for given fields. Probably like the OP, I have a deep structure with a few Big Decimal here and there and it fails equals if one BigDecimal field is 1 and the other one 1.0
I'd also vote for reopening this issue
Is this issue going to be fixed anytime in future? Because equals generated by lombok isn't very useful in case we have some fields of BigDecimal. That would be great if this equal check on BigDecimal replaced by compareTo.
@nihadibrahimli I don't think that anything should or can be changed as the current behavior is the most correct possible. But now, there's a workaround, working exactly as described years ago.
We are looking into a system to provide method for specific fields, but we're not there yet.
AFAIK the problem is lacking a suitable interface in rt.jar. The problem could be solved the other way round: Use something else in place of a field value (think
writeReplaceorreadResolve). Annotating a field like@EqHC(use=someMethod)isn't refactoring-friendly (*), but we don't have to specify that "someMethod" gets used exactly _instead of_ "someField". Just exclude "someField" and include "someMethod" like in@EqualsAndHashCode class MyClass { @EqualsAndHashCode.Exclude private BigDecimal myDecimal; @EqualsAndHashCode.Include private Object myDecimalForEqHC() { return myDecimal.stripTrailingZeros(); } }It's a bit verbose, but still much shorter and cleaner than writing your own. It also solves #1223 and this idea could be used as a workaround for #1262 and other issues where a _single field_ prevents using Lombok for the _whole class_. Just allow no-args methods to be used as if they were fields.
Oh, by the way, beware that if the equals returns true, the hashCodes should also be the same. How would you do that?
The OP's idea of using
compareTodon't seem to work together withhashCode, but usingequals/hashCodeon a no-arg method's result is fine.(*) I'm assuming you want to deprecate
ofandexcludesome day.
Please note that this solution is not null-safe.
A null-safe solution would be:
@EqualsAndHashCode.Include
private BigDecimal equalsMyDecimal() {
return myDecimal != null ? myDecimal.stripTrailingZeros() : null;
}
Why not Lombok generates exactly how it is explained by @Maaartinus? Ok, maybe with some options on the annotation @EqualsAndHashCode(bigDecimalMessAvoided=true) ?
Just guessing:
1) It extends the annotation with a parameter that more than 99% of the Lombok users will never need. It could lead to confusion for users, and increases the maintenance costs for the Lombok team.
2) There is an easy workaround. Even better, this workaround _makes it clearly visible_ that you deviate from the regular equals, which makes it (imo) an even better solution than an additional parameter.
If you're using BigDecimal in your POJO you'll want correctly generated HC&E methods that ignores scale. That should be more that 99% of developers. When adding new BigDecimal attribute you need to make extra work and is actually more work than when not using Lombok(2 extra annotations and an extra method when on manually will be 2 lines - one in equals, one in hashCode).
OK, I agree it's not clearly that standard HC&E rules does not apply but developer should be aware of this when using BigDecimal.
It would be great to be able to provide a specific equals method for given fields.
This feature remains closed; __the solution Maaartinus posted is already part of lombok__. You don't even have to use the exclude option:
@EqualsAndHashCode
public class Example {
private BigDecimal bd;
@EqualsAndHashCode.include
private BigDecimal bd() {
return bd == null ? null : bd.stripTrailingZeroes();
}
}
though Maaartinus' approach is presumably more readable (a private method named 'bd' doesn't do a great job at communicating what it is for via its name).
Why not Lombok generates exactly how it is explained by @Maaartinus? Ok, maybe with some options on the annotation
@EqualsAndHashCode(bigDecimalMessAvoided=true)?
Because this is impossible:
class Example {
private Object[] ohDear = new Object[] { someBigDecimal };
}
how can lombok possibly figure out that calling Arrays.equals(this.ohDear, other.ohDear) is going to give a wrong result? The same argument can be made for a List<BigDecimal> - do you really want lombok to figure out that it is a list of BigDecimal and thus, that lombok should explicitly iterate through both this.list and other.list to do BD cleanup before comparing/hashcoding? That's... impossible - custom impls of collection concepts exist and lombok cannot possibly be explicitly hardcoded to recognize all of these. Thus, avoidBigDecimalMess = true would be a lie; it would only apply to fields of the BD type itself.
Separately, as janrieke said, if we add avoidBigDecimalMess = true, then I can give you 50 other such exotic features and we (@rspilker and I) are quite certain that this would be a lot worse even without thinking of the crazy maintenance burden that implies.
Silently doing the right thing is an option, except:
private Object o = new BigDecimal(...);), nor if BDs show up in arrays or lists, even if the array/list is properly typed.Thus, it'd be incorrect to silently do this, and it's also incorrect to add a setting or annoparam, thus, this feature remains denied.
Use @EqualsAndHashCode.Include, solves all your problems and also explicitly makes clear in your source code what 'take' on equality you're looking for for your BD field.
Most helpful comment
I don't think this issue should be closed.
It would be great to be able to provide a specific equals method for given fields. Probably like the OP, I have a deep structure with a few
Big Decimalhere and there and it fails equals if oneBigDecimalfield is1and the other one1.0