Line data Source code
1 : // Copyright (C) 2019 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.json; 16 : 17 : import com.google.gerrit.common.Nullable; 18 : import com.google.gson.Gson; 19 : import com.google.gson.JsonSyntaxException; 20 : import com.google.gson.TypeAdapter; 21 : import com.google.gson.TypeAdapterFactory; 22 : import com.google.gson.internal.bind.TypeAdapters; 23 : import com.google.gson.reflect.TypeToken; 24 : import com.google.gson.stream.JsonReader; 25 : import com.google.gson.stream.JsonToken; 26 : import com.google.gson.stream.JsonWriter; 27 : import java.io.IOException; 28 : 29 : /** 30 : * A {@code TypeAdapterFactory} for enums. 31 : * 32 : * <p>This factory introduces a wrapper around Gson's own default enum handler to add the following 33 : * special behavior: log when input which doesn't match any existing enum value is encountered. 34 : */ 35 158 : public class EnumTypeAdapterFactory implements TypeAdapterFactory { 36 : 37 : @SuppressWarnings({"rawtypes", "unchecked"}) 38 : @Nullable 39 : @Override 40 : public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { 41 112 : TypeAdapter<T> defaultEnumAdapter = TypeAdapters.ENUM_FACTORY.create(gson, typeToken); 42 112 : if (defaultEnumAdapter == null) { 43 : // Not an enum. -> Enum type adapter doesn't apply. 44 112 : return null; 45 : } 46 : 47 108 : return new EnumTypeAdapter(defaultEnumAdapter, typeToken); 48 : } 49 : 50 : private static class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> { 51 : 52 : private final TypeAdapter<T> defaultEnumAdapter; 53 : private final TypeToken<T> typeToken; 54 : 55 108 : public EnumTypeAdapter(TypeAdapter<T> defaultEnumAdapter, TypeToken<T> typeToken) { 56 108 : this.defaultEnumAdapter = defaultEnumAdapter; 57 108 : this.typeToken = typeToken; 58 108 : } 59 : 60 : @Override 61 : public T read(JsonReader in) throws IOException { 62 : // Still handle null values. -> Check them first. 63 106 : if (in.peek() == JsonToken.NULL) { 64 1 : in.nextNull(); 65 1 : return null; 66 : } 67 106 : T enumValue = defaultEnumAdapter.read(in); 68 106 : if (enumValue == null) { 69 1 : throw new JsonSyntaxException( 70 1 : String.format("Expected an existing value for enum %s.", typeToken)); 71 : } 72 106 : return enumValue; 73 : } 74 : 75 : @Override 76 : public void write(JsonWriter out, T value) throws IOException { 77 107 : defaultEnumAdapter.write(out, value); 78 107 : } 79 : } 80 : }