001package net.bramp.ffmpeg.gson; 002 003import static com.google.common.base.Preconditions.checkNotNull; 004 005import com.google.common.base.Optional; 006import com.google.gson.TypeAdapter; 007import com.google.gson.stream.JsonReader; 008import com.google.gson.stream.JsonToken; 009import com.google.gson.stream.JsonWriter; 010import java.io.IOException; 011import java.lang.reflect.Field; 012import java.lang.reflect.InvocationTargetException; 013 014/** 015 * Converts a json object which represents a set of booleans. For example: 016 * 017 * <pre> 018 * <code> 019 * public class Set { 020 * public boolean a = true; 021 * public boolean b = false; 022 * public int c = 1; 023 * public int d = 0; 024 * } 025 * </code> 026 * </pre> 027 * 028 * is turned into: 029 * 030 * <pre> 031 * { 032 * "a": true, 033 * "b": false, 034 * "c": true, 035 * "d": false 036 * } 037 * </pre> 038 */ 039public class NamedBitsetAdapter<T> extends TypeAdapter<T> { 040 041 final Class<T> clazz; 042 043 public NamedBitsetAdapter(Class<T> clazz) { 044 this.clazz = checkNotNull(clazz); 045 } 046 047 protected Optional<Boolean> readBoolean(JsonReader reader) throws IOException { 048 JsonToken next = reader.peek(); 049 switch (next) { 050 case BOOLEAN: 051 return Optional.of(reader.nextBoolean()); 052 case NUMBER: 053 return Optional.of(reader.nextInt() != 0); 054 default: 055 reader.skipValue(); 056 return Optional.absent(); 057 } 058 } 059 060 protected void setField(T target, String name, boolean value) throws IllegalAccessException { 061 try { 062 Field f = clazz.getField(name); 063 if ((boolean.class.equals(f.getType()))) { 064 f.setBoolean(target, value); 065 } else if (int.class.equals(f.getType())) { 066 f.setInt(target, value ? 1 : 0); 067 } 068 069 } catch (NoSuchFieldException e) { 070 // Just continue 071 } 072 } 073 074 @Override 075 public T read(JsonReader reader) throws IOException { 076 077 JsonToken next = reader.peek(); 078 079 if (next == JsonToken.NULL) { 080 reader.nextNull(); 081 return null; 082 } 083 084 try { 085 T obj = clazz.getDeclaredConstructor().newInstance(); 086 reader.beginObject(); 087 088 next = reader.peek(); 089 while (next != JsonToken.END_OBJECT) { 090 String name = reader.nextName(); 091 Optional<Boolean> value = readBoolean(reader); 092 093 if (value.isPresent()) { 094 setField(obj, name, value.get()); 095 } 096 097 next = reader.peek(); 098 } 099 100 reader.endObject(); 101 return obj; 102 103 } catch (InstantiationException 104 | IllegalAccessException 105 | NoSuchMethodException 106 | InvocationTargetException e) { 107 throw new IOException("Reflection error", e); 108 } 109 } 110 111 @Override 112 public void write(JsonWriter writer, T value) throws IOException { 113 114 if (value == null) { 115 writer.nullValue(); 116 return; 117 } 118 119 assert value.getClass().equals(clazz); 120 121 writer.beginObject(); 122 for (Field f : clazz.getFields()) { 123 try { 124 boolean b; 125 if (boolean.class.equals(f.getType())) { 126 b = f.getBoolean(value); 127 } else if (int.class.equals(f.getType())) { 128 b = f.getInt(value) != 0; 129 } else { 130 continue; 131 } 132 133 writer.name(f.getName()); 134 writer.value(b); 135 136 } catch (IllegalAccessException e) { 137 throw new IOException("Reflection error", e); 138 } 139 } 140 writer.endObject(); 141 } 142}