Hi team,
For a specific reason, I want 2 decimal places for my double when serializing into JSON.
Something like:
9900 --> 9900.00
9900.0 --> 9900.00
9900.1234 --> 9900.12
My best result so far:
9900 --> 9900.0
9900.0 --> 9900.0
9900.1234 --> 9900.12
My DoubleAdapter.java, please advice. Thanks a lot!
class DoubleAdapter extends TypeAdapter<Double> {
@Override
public void write(JsonWriter jsonWriter, Double aDouble) throws IOException {
DecimalFormat df = new DecimalFormat("0.00");
jsonWriter.value(Double.valueOf(df.format(aDouble)));
}
@Override
public Double read(JsonReader jsonReader) throws IOException {
return jsonReader.nextDouble();
}
}
JsonWriter does not support it AFAIR (and I do believe it's totally fine). Just curious: what's the rationale of your case?
It looks like there are at least two hacky workarounds:
JsonWriter.jsonValue(String)java.lang.Number subclass which implements toString() by using a DecimalFormat.Number.toString(). Additionally you should implement all Number methods to get correct behavior in case the JsonWriter is a JsonTreeWriter at runtime: // ThreadLocal because DecimalFormat is not thread-safe
private static final ThreadLocal<DecimalFormat> format =
// Specify DecimalFormatSymbols to make code independent from default Locale
ThreadLocal.withInitial(() -> new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.ENGLISH)));
private final Double delegate;
public FormattedDouble(Double value) {
// Possibly also have to add a Objects.requireNonNull here
this.delegate = value;
}
@Override public byte byteValue() {
return delegate.byteValue();
}
@Override public short shortValue() {
return delegate.shortValue();
}
@Override public int intValue() {
return delegate.intValue();
}
@Override public long longValue() {
return delegate.longValue();
}
@Override public float floatValue() {
return delegate.floatValue();
}
@Override public double doubleValue() {
return delegate.doubleValue();
}
@Override public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof FormattedDouble) {
return ((FormattedDouble) obj).delegate.equals(delegate);
} else {
return false;
}
}
@Override public int hashCode() {
return 31 * delegate.hashCode() + format.get().hashCode();
}
@Override public String toString() {
return format.get().format((double) delegate);
}
}
```
And then use it like this:
```java
@Override
public void write(JsonWriter jsonWriter, Double aDouble) throws IOException {
// Possibly also have to add a null check here
jsonWriter.value(new FormattedDouble(aDouble));
}
```
@Marcono1234
oh, I totally forgot that JsonWriter can write arbitrary Number implementations relying on their possibly unsafe toString methods that may cause Gson to produce illegal JSONs.
Most helpful comment
It looks like there are at least two hacky workarounds:
JsonWriter.jsonValue(String)Note however that this method should be avoided unless you know for sure that the JsonWriter is not a JsonTreeWriter at runtime, see #1651.
java.lang.Numbersubclass which implementstoString()by using aDecimalFormat.However this relies on the implementation detail that Gson internally uses
Number.toString(). Additionally you should implement allNumbermethods to get correct behavior in case the JsonWriter is a JsonTreeWriter at runtime:```java
public class FormattedDouble extends Number {
private static final long serialVersionUID = 1L;