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}