Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

00 as decimal places when serialize Double #1769

Open
TLHP opened this issue Aug 27, 2020 · 3 comments
Open

00 as decimal places when serialize Double #1769

TLHP opened this issue Aug 27, 2020 · 3 comments

Comments

@TLHP
Copy link

TLHP commented Aug 27, 2020

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();
    }
}
@lyubomyr-shaydariv
Copy link
Contributor

JsonWriter does not support it AFAIR (and I do believe it's totally fine). Just curious: what's the rationale of your case?

@Marcono1234
Copy link
Collaborator

Marcono1234 commented Aug 29, 2020

It looks like there are at least two hacky workarounds:

  1. Use 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 Throw UnsupportedOperationException when JsonWriter.jsonValue is not supported #1651.
  2. Create a custom java.lang.Number subclass which implements toString() by using a DecimalFormat.
    However this relies on the implementation detail that Gson internally uses Number.toString(). Additionally you should implement all Number methods to get correct behavior in case the JsonWriter is a JsonTreeWriter at runtime:
    public class FormattedDouble extends Number {
        private static final long serialVersionUID = 1L;
    
        // 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:
    @Override
    public void write(JsonWriter jsonWriter, Double aDouble) throws IOException {
        // Possibly also have to add a null check here
        jsonWriter.value(new FormattedDouble(aDouble));
    }

@lyubomyr-shaydariv
Copy link
Contributor

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants