diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackDateAdapter.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackDateAdapter.java index 4835a509b4..c44c5874f8 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackDateAdapter.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackDateAdapter.java @@ -18,17 +18,15 @@ */ package org.jclouds.cloudstack.config; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonElement; -import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import org.jclouds.date.DateService; -import org.jclouds.json.config.GsonModule; +import java.io.IOException; +import java.util.Date; import javax.inject.Inject; -import java.lang.reflect.Type; -import java.util.Date; + +import org.jclouds.date.DateService; +import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; + +import com.google.gson.stream.JsonReader; /** * Data adapter for the date formats used by CloudStack. @@ -39,27 +37,15 @@ import java.util.Date; * * @author Richard Downer */ -public class CloudStackDateAdapter implements GsonModule.DateAdapter { - private final DateService dateService; +public class CloudStackDateAdapter extends Iso8601DateAdapter { @Inject private CloudStackDateAdapter(DateService dateService) { - this.dateService = dateService; + super(dateService); } - public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(dateService.iso8601DateFormat(src)); - } - - public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - String toParse = json.getAsJsonPrimitive().getAsString(); - toParse = toParse.replaceAll("'T'", "T"); - try { - return dateService.iso8601DateParse(toParse); - } catch (RuntimeException e) { - return dateService.iso8601SecondsDateParse(toParse); - } + public Date read(JsonReader reader) throws IOException { + return parseDate(reader.nextString().replaceAll("'T'", "T")); } } diff --git a/core/src/main/java/org/jclouds/json/config/GsonModule.java b/core/src/main/java/org/jclouds/json/config/GsonModule.java index ada6cb1ec2..aaece5b7fa 100644 --- a/core/src/main/java/org/jclouds/json/config/GsonModule.java +++ b/core/src/main/java/org/jclouds/json/config/GsonModule.java @@ -18,14 +18,13 @@ */ package org.jclouds.json.config; +import java.io.IOException; import java.lang.reflect.Type; import java.util.Date; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.inject.Inject; import javax.inject.Singleton; @@ -48,10 +47,13 @@ import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; +import com.google.gson.TypeAdapter; +import com.google.gson.internal.JsonReaderInternalAccess; import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; import com.google.inject.AbstractModule; import com.google.inject.ImplementedBy; import com.google.inject.Provides; @@ -68,20 +70,25 @@ public class GsonModule extends AbstractModule { @Provides @Singleton Gson provideGson(JsonBallAdapter jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter, - ByteArrayAdapter byteArrayAdapter, SerializePropertiesDefaults propertiesAdapter, - JsonAdapterBindings bindings) throws ClassNotFoundException, Exception { + ByteArrayAdapter byteArrayAdapter, PropertiesAdapter propertiesAdapter, JsonAdapterBindings bindings) + throws ClassNotFoundException, Exception { GsonBuilder builder = new GsonBuilder(); - Logger.getLogger("com.google.gson.ParameterizedTypeHandlerMap").setLevel(Level.OFF); + + // simple (type adapters) + builder.registerTypeAdapter(Properties.class, propertiesAdapter.nullSafe()); + builder.registerTypeAdapter(Date.class, adapter.nullSafe()); + builder.registerTypeAdapter(new TypeToken>() { + }.getType(), byteListAdapter.nullSafe()); + builder.registerTypeAdapter(byte[].class, byteArrayAdapter.nullSafe()); + + // complicated (serializers/deserializers as they need context to operate) builder.registerTypeHierarchyAdapter(Enum.class, new EnumTypeAdapterThatReturnsFromValue()); builder.registerTypeAdapter(JsonBall.class, jsonAdapter); - builder.registerTypeAdapter(Date.class, adapter); - builder.registerTypeAdapter(Properties.class, propertiesAdapter); - builder.registerTypeAdapter(new TypeToken>() { - }.getType(), byteListAdapter); - builder.registerTypeAdapter(byte[].class, byteArrayAdapter); + for (Map.Entry binding : bindings.getBindings().entrySet()) { builder.registerTypeAdapter(binding.getKey(), binding.getValue()); } + return builder.create(); } @@ -99,74 +106,74 @@ public class GsonModule extends AbstractModule { } public JsonBall deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { + throws JsonParseException { return new JsonBall(json.toString()); } } @ImplementedBy(CDateAdapter.class) - public static interface DateAdapter extends JsonSerializer, JsonDeserializer { + public static abstract class DateAdapter extends TypeAdapter { } @ImplementedBy(HexByteListAdapter.class) - public static interface ByteListAdapter extends JsonSerializer>, JsonDeserializer> { + public static abstract class ByteListAdapter extends TypeAdapter> { } @ImplementedBy(HexByteArrayAdapter.class) - public static interface ByteArrayAdapter extends JsonSerializer, JsonDeserializer { + public static abstract class ByteArrayAdapter extends TypeAdapter { } @Singleton - public static class HexByteListAdapter implements ByteListAdapter { + public static class HexByteListAdapter extends ByteListAdapter { @Override - public List deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - return Bytes.asList(CryptoStreams.hex(json.getAsString())); + public void write(JsonWriter writer, List value) throws IOException { + writer.value(CryptoStreams.hex(Bytes.toArray(value))); } @Override - public JsonElement serialize(List src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(CryptoStreams.hex(Bytes.toArray(src))); + public List read(JsonReader reader) throws IOException { + return Bytes.asList(CryptoStreams.hex(reader.nextString())); } } @Singleton - public static class HexByteArrayAdapter implements ByteArrayAdapter { + public static class HexByteArrayAdapter extends ByteArrayAdapter { @Override - public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - return CryptoStreams.hex(json.getAsString()); + public void write(JsonWriter writer, byte[] value) throws IOException { + writer.value(CryptoStreams.hex(value)); } @Override - public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(CryptoStreams.hex(src)); + public byte[] read(JsonReader reader) throws IOException { + return CryptoStreams.hex(reader.nextString()); } } @Singleton - public static class Iso8601DateAdapter implements DateAdapter { + public static class Iso8601DateAdapter extends DateAdapter { private final DateService dateService; @Inject - private Iso8601DateAdapter(DateService dateService) { + public Iso8601DateAdapter(DateService dateService) { this.dateService = dateService; } - public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(dateService.iso8601DateFormat(src)); + public void write(JsonWriter writer, Date value) throws IOException { + writer.value(dateService.iso8601DateFormat(value)); } - public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - String toParse = json.getAsJsonPrimitive().getAsString(); + public Date read(JsonReader reader) throws IOException { + return parseDate(reader.nextString()); + } + + protected Date parseDate(String toParse) { try { return dateService.iso8601DateParse(toParse); } catch (RuntimeException e) { @@ -177,63 +184,71 @@ public class GsonModule extends AbstractModule { } @Singleton - public static class SerializePropertiesDefaults implements JsonSerializer { + public static class PropertiesAdapter extends TypeAdapter { private final Json json; private final Type mapType = new TypeLiteral>() { }.getRawType(); @Inject - public SerializePropertiesDefaults(Json json) { + public PropertiesAdapter(Json json) { this.json = json; } - - public JsonElement serialize(Properties src, Type typeOfSrc, JsonSerializationContext context) { + + @Override + public void write(JsonWriter out, Properties value) throws IOException { Builder srcMap = ImmutableMap. builder(); - for (Enumeration propNames = src.propertyNames(); propNames.hasMoreElements();) { + for (Enumeration propNames = value.propertyNames(); propNames.hasMoreElements();) { String propName = (String) propNames.nextElement(); - srcMap.put(propName, src.getProperty(propName)); + srcMap.put(propName, value.getProperty(propName)); } - return new JsonLiteral(json.toJson(srcMap.build(), mapType)); + out.value(new JsonLiteral(json.toJson(srcMap.build(), mapType))); + } + + @Override + public Properties read(JsonReader in) throws IOException { + Properties props = new Properties(); + in.beginObject(); + while (in.hasNext()) { + JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in); + props.setProperty(in.nextString(), in.nextString()); + } + in.endObject(); + return props; } } @Singleton - public static class CDateAdapter implements DateAdapter { + public static class CDateAdapter extends DateAdapter { private final DateService dateService; @Inject - private CDateAdapter(DateService dateService) { + public CDateAdapter(DateService dateService) { this.dateService = dateService; } - public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(dateService.cDateFormat(src)); + public void write(JsonWriter writer, Date value) throws IOException { + writer.value(dateService.cDateFormat(value)); } - public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - String toParse = json.getAsJsonPrimitive().getAsString(); - Date toReturn = dateService.cDateParse(toParse); - return toReturn; + public Date read(JsonReader reader) throws IOException { + return dateService.cDateParse(reader.nextString()); } } @Singleton - public static class LongDateAdapter implements DateAdapter { + public static class LongDateAdapter extends DateAdapter { - public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(src.getTime()); + public void write(JsonWriter writer, Date value) throws IOException { + writer.value(value.getTime()); } - public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - long toParse = json.getAsJsonPrimitive().getAsLong(); + public Date read(JsonReader reader) throws IOException { + long toParse = reader.nextLong(); if (toParse == -1) return null; - Date toReturn = new Date(toParse); - return toReturn; + return new Date(toParse); } } diff --git a/providers/gogrid/src/main/java/org/jclouds/gogrid/config/DateSecondsAdapter.java b/providers/gogrid/src/main/java/org/jclouds/gogrid/config/DateSecondsAdapter.java deleted file mode 100644 index 985b5e49a1..0000000000 --- a/providers/gogrid/src/main/java/org/jclouds/gogrid/config/DateSecondsAdapter.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.gogrid.config; - -import java.lang.reflect.Type; -import java.util.Date; - -import javax.inject.Singleton; - -import org.jclouds.json.config.GsonModule.DateAdapter; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonElement; -import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; - -/** - * Configures the GoGrid connection, including logging and http transport. - * - * @author Adrian Cole - * @author Oleksiy Yarmula - */ -@Singleton -public class DateSecondsAdapter implements DateAdapter { - - public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(src.getTime()); - } - - public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - String toParse = json.getAsJsonPrimitive().getAsString(); - return new Date(Long.valueOf(toParse)); - } -} \ No newline at end of file diff --git a/providers/gogrid/src/main/java/org/jclouds/gogrid/config/GoGridParserModule.java b/providers/gogrid/src/main/java/org/jclouds/gogrid/config/GoGridParserModule.java index d5205b7636..41626cbf9f 100644 --- a/providers/gogrid/src/main/java/org/jclouds/gogrid/config/GoGridParserModule.java +++ b/providers/gogrid/src/main/java/org/jclouds/gogrid/config/GoGridParserModule.java @@ -35,6 +35,7 @@ import org.jclouds.gogrid.domain.ServerImageType; import org.jclouds.gogrid.domain.ServerState; import org.jclouds.gogrid.functions.internal.CustomDeserializers; import org.jclouds.json.config.GsonModule.DateAdapter; +import org.jclouds.json.config.GsonModule.LongDateAdapter; import com.google.common.collect.Maps; import com.google.inject.AbstractModule; @@ -68,7 +69,7 @@ public class GoGridParserModule extends AbstractModule { @Override protected void configure() { - bind(DateAdapter.class).to(DateSecondsAdapter.class); + bind(DateAdapter.class).to(LongDateAdapter.class); } } \ No newline at end of file diff --git a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseCredentialsFromJsonResponseTest.java b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseCredentialsFromJsonResponseTest.java index 5aa76384bd..3590f10369 100644 --- a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseCredentialsFromJsonResponseTest.java +++ b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseCredentialsFromJsonResponseTest.java @@ -28,7 +28,6 @@ import java.util.Map; import javax.inject.Singleton; import org.jclouds.domain.Credentials; -import org.jclouds.gogrid.config.DateSecondsAdapter; import org.jclouds.gogrid.domain.IpState; import org.jclouds.gogrid.domain.ServerImageState; import org.jclouds.gogrid.domain.ServerImageType; @@ -77,7 +76,7 @@ public class ParseCredentialsFromJsonResponseTest { Injector i = Guice.createInjector(new GsonModule() { @Override protected void configure() { - bind(DateAdapter.class).to(DateSecondsAdapter.class); + bind(DateAdapter.class).to(LongDateAdapter.class); super.configure(); } diff --git a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseErrorFromJsonResponseTest.java b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseErrorFromJsonResponseTest.java index 7f8169a841..9121038706 100644 --- a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseErrorFromJsonResponseTest.java +++ b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseErrorFromJsonResponseTest.java @@ -21,7 +21,6 @@ package org.jclouds.gogrid.functions; import java.io.InputStream; import java.net.UnknownHostException; -import org.jclouds.gogrid.config.DateSecondsAdapter; import org.jclouds.gogrid.domain.internal.ErrorResponse; import org.jclouds.http.HttpResponse; import org.jclouds.io.Payloads; @@ -42,7 +41,7 @@ public class ParseErrorFromJsonResponseTest { Injector i = Guice.createInjector(new GsonModule() { @Override protected void configure() { - bind(DateAdapter.class).to(DateSecondsAdapter.class); + bind(DateAdapter.class).to(LongDateAdapter.class); super.configure(); } }); diff --git a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseJobsFromJsonResponseTest.java b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseJobsFromJsonResponseTest.java index c699dc496a..a5f5d7de6f 100644 --- a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseJobsFromJsonResponseTest.java +++ b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseJobsFromJsonResponseTest.java @@ -29,7 +29,6 @@ import java.util.SortedSet; import javax.inject.Singleton; -import org.jclouds.gogrid.config.DateSecondsAdapter; import org.jclouds.gogrid.domain.Job; import org.jclouds.gogrid.domain.JobProperties; import org.jclouds.gogrid.domain.JobState; @@ -80,7 +79,7 @@ public class ParseJobsFromJsonResponseTest { Injector i = Guice.createInjector(new GsonModule() { @Override protected void configure() { - bind(DateAdapter.class).to(DateSecondsAdapter.class); + bind(DateAdapter.class).to(LongDateAdapter.class); super.configure(); } diff --git a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseLoadBalancersFromJsonResponseTest.java b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseLoadBalancersFromJsonResponseTest.java index a936bd61a6..d697f86fb4 100644 --- a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseLoadBalancersFromJsonResponseTest.java +++ b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseLoadBalancersFromJsonResponseTest.java @@ -28,7 +28,6 @@ import java.util.SortedSet; import javax.inject.Singleton; -import org.jclouds.gogrid.config.DateSecondsAdapter; import org.jclouds.gogrid.domain.Ip; import org.jclouds.gogrid.domain.IpPortPair; import org.jclouds.gogrid.domain.IpState; @@ -79,7 +78,7 @@ public class ParseLoadBalancersFromJsonResponseTest { Injector i = Guice.createInjector(new GsonModule() { @Override protected void configure() { - bind(DateAdapter.class).to(DateSecondsAdapter.class); + bind(DateAdapter.class).to(LongDateAdapter.class); super.configure(); } diff --git a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseServerNameToCredentialsMapFromJsonResponseTest.java b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseServerNameToCredentialsMapFromJsonResponseTest.java index a86a3e6660..f9559066e5 100644 --- a/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseServerNameToCredentialsMapFromJsonResponseTest.java +++ b/providers/gogrid/src/test/java/org/jclouds/gogrid/functions/ParseServerNameToCredentialsMapFromJsonResponseTest.java @@ -28,7 +28,6 @@ import java.util.Map; import javax.inject.Singleton; import org.jclouds.domain.Credentials; -import org.jclouds.gogrid.config.DateSecondsAdapter; import org.jclouds.gogrid.domain.IpState; import org.jclouds.gogrid.domain.ServerImageState; import org.jclouds.gogrid.domain.ServerImageType; @@ -65,7 +64,7 @@ public class ParseServerNameToCredentialsMapFromJsonResponseTest { Injector i = Guice.createInjector(new GsonModule() { @Override protected void configure() { - bind(DateAdapter.class).to(DateSecondsAdapter.class); + bind(DateAdapter.class).to(LongDateAdapter.class); super.configure(); } diff --git a/providers/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/config/RimuHostingRestClientModule.java b/providers/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/config/RimuHostingRestClientModule.java index c7b5071efb..56f6562e5f 100644 --- a/providers/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/config/RimuHostingRestClientModule.java +++ b/providers/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/config/RimuHostingRestClientModule.java @@ -18,7 +18,7 @@ */ package org.jclouds.rimuhosting.miro.config; -import java.lang.reflect.Type; +import java.io.IOException; import java.util.Date; import javax.inject.Inject; @@ -26,17 +26,16 @@ import javax.inject.Singleton; import org.jclouds.date.DateService; import org.jclouds.http.RequiresHttp; -import org.jclouds.json.Json; +import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule.DateAdapter; +import org.jclouds.json.config.GsonModule.PropertiesAdapter; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.config.RestClientModule; import org.jclouds.rimuhosting.miro.RimuHostingAsyncClient; import org.jclouds.rimuhosting.miro.RimuHostingClient; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonElement; -import com.google.gson.JsonParseException; -import com.google.gson.JsonSerializationContext; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; /** * @@ -57,29 +56,25 @@ public class RimuHostingRestClientModule extends RestClientModule