From 79606f94ebb240286fc4b700d6dd4482697e8905 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 30 Oct 2014 09:22:28 -0700 Subject: [PATCH] Use type adapter factory to hard-set serialization of Credentials. --- .../org/jclouds/json/config/GsonModule.java | 70 ++++++++++++++++++- .../rest/config/CredentialStoreModule.java | 40 ++--------- 2 files changed, 73 insertions(+), 37 deletions(-) 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 1dd53dafd7..4c62be7df6 100644 --- a/core/src/main/java/org/jclouds/json/config/GsonModule.java +++ b/core/src/main/java/org/jclouds/json/config/GsonModule.java @@ -32,7 +32,9 @@ import javax.inject.Provider; import javax.inject.Singleton; import org.jclouds.date.DateService; +import org.jclouds.domain.Credentials; import org.jclouds.domain.JsonBall; +import org.jclouds.domain.LoginCredentials; import org.jclouds.json.Json; import org.jclouds.json.SerializedNames; import org.jclouds.json.internal.DeserializationConstructorAndReflectiveTypeAdapterFactory; @@ -94,8 +96,9 @@ public class GsonModule extends AbstractModule { @Singleton Gson provideGson(TypeAdapter jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter, ByteArrayAdapter byteArrayAdapter, PropertiesAdapter propertiesAdapter, JsonAdapterBindings bindings, - OptionalTypeAdapterFactory optional, SetTypeAdapterFactory set, ImmutableSetTypeAdapterFactory immutableSet, - MapTypeAdapterFactory map, MultimapTypeAdapterFactory multimap, IterableTypeAdapterFactory iterable, + CredentialsAdapterFactory credentialsAdapterFactory, OptionalTypeAdapterFactory optional, + SetTypeAdapterFactory set, ImmutableSetTypeAdapterFactory immutableSet, MapTypeAdapterFactory map, + MultimapTypeAdapterFactory multimap, IterableTypeAdapterFactory iterable, CollectionTypeAdapterFactory collection, ListTypeAdapterFactory list, ImmutableListTypeAdapterFactory immutableList, FluentIterableTypeAdapterFactory fluentIterable, ImmutableMapTypeAdapterFactory immutableMap, DefaultExclusionStrategy exclusionStrategy, @@ -112,6 +115,7 @@ public class GsonModule extends AbstractModule { builder.registerTypeAdapter(Date.class, adapter.nullSafe()); builder.registerTypeAdapter(byte[].class, byteArrayAdapter.nullSafe()); builder.registerTypeAdapter(JsonBall.class, jsonAdapter.nullSafe()); + builder.registerTypeAdapterFactory(credentialsAdapterFactory); builder.registerTypeAdapterFactory(optional); builder.registerTypeAdapterFactory(iterable); builder.registerTypeAdapterFactory(collection); @@ -316,6 +320,68 @@ public class GsonModule extends AbstractModule { } } + /** Special cases serialization for {@linkplain LoginCredentials} and normalizes all others. */ + public static class CredentialsAdapterFactory extends TypeAdapter implements TypeAdapterFactory { + + @Override public void write(JsonWriter out, Credentials credentials) throws IOException { + out.beginObject(); + if (credentials instanceof LoginCredentials) { + LoginCredentials login = (LoginCredentials) credentials; + out.name("user"); + out.value(login.getUser()); + out.name("password"); + out.value(login.getOptionalPassword().orNull()); + out.name("privateKey"); + out.value(login.getOptionalPrivateKey().orNull()); + if (login.shouldAuthenticateSudo()) { + out.name("authenticateSudo"); + out.value(login.shouldAuthenticateSudo()); + } + } else { + out.name("identity"); + out.value(credentials.identity); + out.name("credential"); + out.value(credentials.credential); + } + out.endObject(); + } + + @Override public Credentials read(JsonReader in) throws IOException { + LoginCredentials.Builder builder = LoginCredentials.builder(); + String identity = null; + String credential = null; + in.beginObject(); + while (in.hasNext()) { + String name = in.nextName(); + if (name.equals("identity")) { + identity = in.nextString(); + } else if (name.equals("credential")) { + credential = in.nextString(); + } else if (name.equals("user")) { + builder.user(in.nextString()); + } else if (name.equals("password")) { + builder.password(in.nextString()); + } else if (name.equals("privateKey")) { + builder.privateKey(in.nextString()); + } else if (name.equals("authenticateSudo")) { + builder.authenticateSudo(in.nextBoolean()); + } else { + in.skipValue(); + } + } + in.endObject(); + LoginCredentials result = builder.build(); + return result != null ? result : new Credentials(identity, credential); + } + + @Override public TypeAdapter create(Gson gson, TypeToken typeToken) { + if (!(Credentials.class.isAssignableFrom(typeToken.getRawType()))) { + return null; + } + return (TypeAdapter) this; + } + } + @Singleton public static class JsonAdapterBindings { private final Map bindings = Maps.newHashMap(); diff --git a/core/src/main/java/org/jclouds/rest/config/CredentialStoreModule.java b/core/src/main/java/org/jclouds/rest/config/CredentialStoreModule.java index 8e7e5087a0..180d89d3ba 100644 --- a/core/src/main/java/org/jclouds/rest/config/CredentialStoreModule.java +++ b/core/src/main/java/org/jclouds/rest/config/CredentialStoreModule.java @@ -27,7 +27,6 @@ import javax.inject.Singleton; import org.jclouds.collect.TransformingMap; import org.jclouds.domain.Credentials; -import org.jclouds.domain.LoginCredentials; import org.jclouds.json.Json; import org.jclouds.logging.Logger; import org.jclouds.rest.ConfiguresCredentialStore; @@ -69,62 +68,33 @@ public class CredentialStoreModule extends AbstractModule { } } - @Singleton public static class CredentialsToJsonByteSource implements Function { private final Json json; - @Inject - CredentialsToJsonByteSource(Json json) { + @Inject CredentialsToJsonByteSource(Json json) { this.json = json; } - @Override - public ByteSource apply(Credentials from) { + @Override public ByteSource apply(Credentials from) { checkNotNull(from, "inputCredentials"); - if (from instanceof LoginCredentials) { - LoginCredentials login = LoginCredentials.class.cast(from); - JsonLoginCredentials val = new JsonLoginCredentials(); - val.user = login.getUser(); - val.password = login.getOptionalPassword().orNull(); - val.privateKey = login.getOptionalPrivateKey().orNull(); - if (login.shouldAuthenticateSudo()) - val.authenticateSudo = login.shouldAuthenticateSudo(); - return ByteSource.wrap(json.toJson(val).getBytes(Charsets.UTF_8)); - } return ByteSource.wrap(json.toJson(from).getBytes(Charsets.UTF_8)); } } - static class JsonLoginCredentials { - private String user; - private String password; - private String privateKey; - private Boolean authenticateSudo; - } - - @Singleton public static class CredentialsFromJsonByteSource implements Function { @Resource protected Logger logger = Logger.NULL; private final Json json; - @Inject - CredentialsFromJsonByteSource(Json json) { + @Inject CredentialsFromJsonByteSource(Json json) { this.json = json; } - @Override - public Credentials apply(ByteSource from) { + @Override public Credentials apply(ByteSource from) { try { String creds = (checkNotNull(from)).asCharSource(Charsets.UTF_8).read(); - if (creds.indexOf("\"user\":") == -1) { - return json.fromJson(creds, Credentials.class); - } else { - JsonLoginCredentials val = json.fromJson(creds, JsonLoginCredentials.class); - return LoginCredentials.builder().user(val.user).password(val.password).privateKey(val.privateKey) - .authenticateSudo(Boolean.TRUE.equals(val.authenticateSudo)).build(); - } + return json.fromJson(creds, Credentials.class); } catch (Exception e) { logger.warn(e, "ignoring problem retrieving credentials"); return null;