001package net.bramp.ffmpeg.gson;
002
003import static com.google.common.base.Preconditions.checkNotNull;
004
005import com.google.common.collect.ImmutableMap;
006import com.google.errorprone.annotations.Immutable;
007import com.google.gson.Gson;
008import com.google.gson.TypeAdapter;
009import com.google.gson.TypeAdapterFactory;
010import com.google.gson.reflect.TypeToken;
011import com.google.gson.stream.JsonReader;
012import com.google.gson.stream.JsonToken;
013import com.google.gson.stream.JsonWriter;
014import java.io.IOException;
015import java.util.HashMap;
016import java.util.Locale;
017import java.util.Map;
018import javax.annotation.CheckReturnValue;
019import javax.annotation.Nonnull;
020
021/**
022 * Maps Enums to lowercase strings.
023 *
024 * <p>Adapted from: <a href=
025 * "https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/TypeAdapterFactory.html"
026 * >TypeAdapterFactory</a>
027 */
028@Immutable
029public class LowercaseEnumTypeAdapterFactory implements TypeAdapterFactory {
030
031  @Immutable
032  private static class MyTypeAdapter<T> extends TypeAdapter<T> {
033
034    // T is a Enum, thus immutable, however, we can't enforce that type due to the
035    // TypeAdapterFactory interface
036    @SuppressWarnings("Immutable")
037    private final ImmutableMap<String, T> lowercaseToEnum;
038
039    public MyTypeAdapter(Map<String, T> lowercaseToEnum) {
040      this.lowercaseToEnum = ImmutableMap.copyOf(lowercaseToEnum);
041    }
042
043    @Override
044    public void write(JsonWriter out, T value) throws IOException {
045      checkNotNull(out);
046
047      if (value == null) {
048        out.nullValue();
049      } else {
050        out.value(toLowercase(value));
051      }
052    }
053
054    @Override
055    public T read(JsonReader reader) throws IOException {
056      checkNotNull(reader);
057
058      if (reader.peek() == JsonToken.NULL) {
059        reader.nextNull();
060        return null;
061      }
062      return lowercaseToEnum.get(reader.nextString());
063    }
064  }
065
066  @CheckReturnValue
067  @Override
068  @SuppressWarnings("unchecked")
069  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
070    checkNotNull(type);
071
072    Class<T> rawType = (Class<T>) type.getRawType();
073    if (!rawType.isEnum()) {
074      return null;
075    }
076
077    // Setup mapping of consts
078    final Map<String, T> lowercaseToEnum = new HashMap<>();
079    for (T constant : rawType.getEnumConstants()) {
080      lowercaseToEnum.put(toLowercase(constant), constant);
081    }
082
083    return new MyTypeAdapter<T>(lowercaseToEnum);
084  }
085
086  @CheckReturnValue
087  private static String toLowercase(@Nonnull Object o) {
088    return checkNotNull(o).toString().toLowerCase(Locale.UK);
089  }
090}