001package net.bramp.commons.lang3.math.gson;
002
003import com.google.errorprone.annotations.Immutable;
004import com.google.gson.TypeAdapter;
005import com.google.gson.stream.JsonReader;
006import com.google.gson.stream.JsonToken;
007import com.google.gson.stream.JsonWriter;
008import java.io.IOException;
009import org.apache.commons.lang3.math.Fraction;
010
011/**
012 * GSON TypeAdapter for Apache Commons Math Fraction Object.
013 *
014 * @author bramp
015 */
016@Immutable
017public class FractionAdapter extends TypeAdapter<Fraction> {
018
019  /** If set, 0/0 returns this value, instead of throwing a ArithmeticException. */
020  @SuppressWarnings(
021      "Immutable") // TODO Remove when https://github.com/google/error-prone/issues/512 is fixed
022  private final Fraction zeroByZero;
023
024  /** If set, N/0 returns this value, instead of throwing a ArithmeticException. */
025  @SuppressWarnings(
026      "Immutable") // TODO Remove when https://github.com/google/error-prone/issues/512 is fixed
027  private final Fraction divideByZero;
028
029  /** Constructs a FractionAdapter with default zero values for edge cases. */
030  public FractionAdapter() {
031    this(Fraction.ZERO, Fraction.ZERO);
032  }
033
034  private FractionAdapter(Fraction zeroByZero, Fraction divideByZero) {
035    this.zeroByZero = zeroByZero;
036    this.divideByZero = divideByZero;
037  }
038
039  @Override
040  public Fraction read(JsonReader reader) throws IOException {
041    JsonToken next = reader.peek();
042
043    if (next == JsonToken.NULL) {
044      reader.nextNull();
045      return null;
046    }
047
048    if (next == JsonToken.NUMBER) {
049      return Fraction.getFraction(reader.nextDouble());
050    }
051
052    String fraction = reader.nextString().trim();
053
054    // Ambiguous as to what 0/0 is, but FFmpeg seems to think it's zero
055    if (zeroByZero != null && "0/0".equals(fraction)) {
056      return zeroByZero;
057    }
058
059    // Another edge cases is invalid files sometimes output 1/0.
060    if (divideByZero != null && fraction.endsWith("/0")) {
061      return divideByZero;
062    }
063
064    return Fraction.getFraction(fraction);
065  }
066
067  @Override
068  public void write(JsonWriter writer, Fraction value) throws IOException {
069    if (value == null) {
070      writer.nullValue();
071      return;
072    }
073    writer.value(value.toProperString());
074  }
075}