Mam implementację schematu JSON napisaną w Javie, która zależy od Jackson (wersja 2.1.x). Ze względu na dokładność mówię Jacksonowi, aby używał BigDecimal
dla liczb zmiennoprzecinkowych."Normalizowanie" Kod skrótu BigDecimal: howto?
Dla potrzeb schematu JSON istnieje szczególne zapotrzebowanie: Równość wartości JSON dla wartości numerycznych jest definiowana przez równość ich wartości matematycznej. Potrzebuję tego rodzaju czeku od, na przykład, nie jest to schemat prawny (wartości w enum
powinny być unikalne):
{ "enum": [ 1, 1.0 ] }
Ale JsonNodes dla 1
i 1.0
nie są równe. Dlatego też zakodowałem implementację Guva o numerze Equivalence i w razie potrzeby używam Set<Equivalence.Wrapper<JsonNode>>
. A ta implementacja powinna działać dla wszystkich typów węzłów, a nie tylko dla węzłów numerycznych.
I najtrudniejsza część tej realizacji okazuje się doHash()
dla węzłów numerycznych:/Muszę ten sam hashcode dla równoważnych wartościach matematycznych, czy są liczbami całkowitymi lub liczb zmiennoprzecinkowych.
Najlepszym mogę wymyślić w tej chwili jest tak:
@Override
protected int doHash(final JsonNode t)
{
/*
* If this is a numeric node, we want a unique hashcode for all possible
* number nodes.
*/
if (t.isNumber()) {
final BigDecimal decimal = t.decimalValue();
try {
return decimal.toBigIntegerExact().hashCode();
} catch (ArithmeticException ignored) {
return decimal.stripTrailingZeros().hashCode();
}
}
// etc etc -- the rest works fine
Jest to w tej chwili najlepsze co mogłem wymyślić.
Czy istnieje lepszy sposób obliczania takiego kodu skrótu?
(edit: pełny kod realizacji Równoważność here)
@zsxwing: doEquivalent jest już overriden - patrz edit, dodałem link do pełnej implementacji – fge
Not clear - czy istnieje problem, że kod nie zwraca kodów równych dla równych wartości, czy też (omyłkowo) próbując zapewnić unikalny kod skrótu dla każdej odrębnej wartości? –
Czy chcesz, aby "1", "1.0", "1,00" zwracały ten sam kod skrótu? Może możesz użyć TreeSet, który nie używa hashCode? – zsxwing