1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.json.config;
20
21 import java.lang.reflect.Type;
22 import java.util.Date;
23 import java.util.Enumeration;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Properties;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32
33 import org.jclouds.crypto.CryptoStreams;
34 import org.jclouds.date.DateService;
35 import org.jclouds.domain.JsonBall;
36 import org.jclouds.json.Json;
37 import org.jclouds.json.internal.EnumTypeAdapterThatReturnsFromValue;
38 import org.jclouds.json.internal.GsonWrapper;
39
40 import com.google.common.collect.ImmutableMap;
41 import com.google.common.collect.ImmutableMap.Builder;
42 import com.google.common.collect.Maps;
43 import com.google.common.primitives.Bytes;
44 import com.google.gson.Gson;
45 import com.google.gson.GsonBuilder;
46 import com.google.gson.JsonDeserializationContext;
47 import com.google.gson.JsonDeserializer;
48 import com.google.gson.JsonElement;
49 import com.google.gson.JsonLiteral;
50 import com.google.gson.JsonParseException;
51 import com.google.gson.JsonPrimitive;
52 import com.google.gson.JsonSerializationContext;
53 import com.google.gson.JsonSerializer;
54 import com.google.gson.ObjectMapTypeAdapter;
55 import com.google.gson.reflect.TypeToken;
56 import com.google.inject.AbstractModule;
57 import com.google.inject.ImplementedBy;
58 import com.google.inject.Provides;
59 import com.google.inject.TypeLiteral;
60
61
62
63
64
65
66 public class GsonModule extends AbstractModule {
67
68 @SuppressWarnings("rawtypes")
69 @Provides
70 @Singleton
71 Gson provideGson(JsonBallAdapter jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter,
72 ByteArrayAdapter byteArrayAdapter, SerializePropertiesDefaults propertiesAdapter,
73 JsonAdapterBindings bindings) throws ClassNotFoundException, Exception {
74 GsonBuilder builder = new GsonBuilder();
75 Logger.getLogger("com.google.gson.ParameterizedTypeHandlerMap").setLevel(Level.OFF);
76 builder.registerTypeHierarchyAdapter(Enum.class, new EnumTypeAdapterThatReturnsFromValue());
77 builder.registerTypeHierarchyAdapter(Map.class, new ObjectMapTypeAdapter());
78 builder.registerTypeAdapter(JsonBall.class, jsonAdapter);
79 builder.registerTypeAdapter(Date.class, adapter);
80 builder.registerTypeAdapter(Properties.class, propertiesAdapter);
81 builder.registerTypeAdapter(new TypeToken<List<Byte>>() {
82 }.getType(), byteListAdapter);
83 builder.registerTypeAdapter(byte[].class, byteArrayAdapter);
84 for (Map.Entry<Type, Object> binding : bindings.getBindings().entrySet()) {
85 builder.registerTypeAdapter(binding.getKey(), binding.getValue());
86 }
87 return builder.create();
88 }
89
90
91 @ImplementedBy(JsonBallAdapterImpl.class)
92 public static interface JsonBallAdapter extends JsonSerializer<JsonBall>, JsonDeserializer<JsonBall> {
93
94 }
95
96 @Singleton
97 public static class JsonBallAdapterImpl implements JsonBallAdapter {
98
99 public JsonElement serialize(JsonBall src, Type typeOfSrc, JsonSerializationContext context) {
100 return new JsonLiteral(src);
101 }
102
103 public JsonBall deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
104 throws JsonParseException {
105 return new JsonBall(json.toString());
106 }
107
108 }
109
110 @ImplementedBy(CDateAdapter.class)
111 public static interface DateAdapter extends JsonSerializer<Date>, JsonDeserializer<Date> {
112
113 }
114
115 @ImplementedBy(HexByteListAdapter.class)
116 public static interface ByteListAdapter extends JsonSerializer<List<Byte>>, JsonDeserializer<List<Byte>> {
117
118 }
119
120 @ImplementedBy(HexByteArrayAdapter.class)
121 public static interface ByteArrayAdapter extends JsonSerializer<byte[]>, JsonDeserializer<byte[]> {
122
123 }
124
125 @Singleton
126 public static class HexByteListAdapter implements ByteListAdapter {
127
128 @Override
129 public List<Byte> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
130 throws JsonParseException {
131 return Bytes.asList(CryptoStreams.hex(json.getAsString()));
132 }
133
134 @Override
135 public JsonElement serialize(List<Byte> src, Type typeOfSrc, JsonSerializationContext context) {
136 return new JsonPrimitive(CryptoStreams.hex(Bytes.toArray(src)));
137 }
138
139 }
140
141 @Singleton
142 public static class HexByteArrayAdapter implements ByteArrayAdapter {
143
144 @Override
145 public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
146 throws JsonParseException {
147 return CryptoStreams.hex(json.getAsString());
148 }
149
150 @Override
151 public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
152 return new JsonPrimitive(CryptoStreams.hex(src));
153 }
154 }
155
156 @Singleton
157 public static class Iso8601DateAdapter implements DateAdapter {
158 private final DateService dateService;
159
160 @Inject
161 private Iso8601DateAdapter(DateService dateService) {
162 this.dateService = dateService;
163 }
164
165 public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
166 return new JsonPrimitive(dateService.iso8601DateFormat(src));
167 }
168
169 public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
170 throws JsonParseException {
171 String toParse = json.getAsJsonPrimitive().getAsString();
172 try {
173 return dateService.iso8601DateParse(toParse);
174 } catch (RuntimeException e) {
175 return dateService.iso8601SecondsDateParse(toParse);
176 }
177 }
178
179 }
180
181 @Singleton
182 public static class SerializePropertiesDefaults implements JsonSerializer<Properties> {
183 private final Json json;
184 private final Type mapType = new TypeLiteral<Map<String, String>>() {
185 }.getRawType();
186
187 @Inject
188 public SerializePropertiesDefaults(Json json) {
189 this.json = json;
190 }
191
192 public JsonElement serialize(Properties src, Type typeOfSrc, JsonSerializationContext context) {
193 Builder<String, String> srcMap = ImmutableMap.<String, String> builder();
194 for (Enumeration<?> propNames = src.propertyNames(); propNames.hasMoreElements();) {
195 String propName = (String) propNames.nextElement();
196 srcMap.put(propName, src.getProperty(propName));
197 }
198 return new JsonLiteral(json.toJson(srcMap.build(), mapType));
199 }
200
201 }
202
203 @Singleton
204 public static class CDateAdapter implements DateAdapter {
205 private final DateService dateService;
206
207 @Inject
208 private CDateAdapter(DateService dateService) {
209 this.dateService = dateService;
210 }
211
212 public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
213 return new JsonPrimitive(dateService.cDateFormat(src));
214 }
215
216 public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
217 throws JsonParseException {
218 String toParse = json.getAsJsonPrimitive().getAsString();
219 Date toReturn = dateService.cDateParse(toParse);
220 return toReturn;
221 }
222
223 }
224
225 @Singleton
226 public static class LongDateAdapter implements DateAdapter {
227
228 public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
229 return new JsonPrimitive(src.getTime());
230 }
231
232 public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
233 throws JsonParseException {
234 long toParse = json.getAsJsonPrimitive().getAsLong();
235 if (toParse == -1)
236 return null;
237 Date toReturn = new Date(toParse);
238 return toReturn;
239 }
240 }
241
242 @Singleton
243 public static class JsonAdapterBindings {
244 private final Map<Type, Object> bindings = Maps.newHashMap();
245
246 @com.google.inject.Inject(optional = true)
247 public void setBindings(Map<Type, Object> bindings) {
248 this.bindings.putAll(bindings);
249 }
250
251 public Map<Type, Object> getBindings() {
252 return bindings;
253 }
254 }
255
256 @Override
257 protected void configure() {
258 bind(Json.class).to(GsonWrapper.class);
259 }
260 }