Skip to content

Commit

Permalink
Migrate Jackson usage to Gson (#26)
Browse files Browse the repository at this point in the history
* replace jackson json parsing with gson

* validate required fields exists when parsing json
  • Loading branch information
lbalmaceda authored and hzalaz committed Jun 3, 2016
1 parent 0a233c2 commit 6b6fa1f
Show file tree
Hide file tree
Showing 19 changed files with 291 additions and 146 deletions.
4 changes: 1 addition & 3 deletions auth0/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ compileJava {

dependencies {
compile 'com.squareup.okhttp:okhttp:2.5.0'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.1'
compile 'com.fasterxml.jackson.core:jackson-core:2.4.1'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.4.1'
compile "com.google.code.gson:gson:2.6.2"

testCompile 'junit:junit:4.12'
testCompile 'org.hamcrest:hamcrest-integration:1.3'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
import com.auth0.authentication.result.Credentials;
import com.auth0.authentication.result.DatabaseUser;
import com.auth0.authentication.result.Delegation;
import com.auth0.authentication.result.JsonRequiredTypeAdapterFactory;
import com.auth0.authentication.result.UserProfile;
import com.auth0.request.AuthenticationRequest;
import com.auth0.request.ParameterizableRequest;
import com.auth0.request.Request;
import com.auth0.request.internal.RequestFactory;
import com.auth0.util.Telemetry;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.OkHttpClient;

Expand Down Expand Up @@ -77,7 +79,7 @@ public class AuthenticationAPIClient {

private final Auth0 auth0;
private final OkHttpClient client;
private final ObjectMapper mapper;
private final Gson gson;
private final RequestFactory factory;

private String defaultDatabaseConnection = DEFAULT_DB_CONNECTION;
Expand All @@ -88,13 +90,13 @@ public class AuthenticationAPIClient {
* @param auth0 account information
*/
public AuthenticationAPIClient(Auth0 auth0) {
this(auth0, new OkHttpClient(), new ObjectMapper());
this(auth0, new OkHttpClient(), buildGson());
}

private AuthenticationAPIClient(Auth0 auth0, OkHttpClient client, ObjectMapper mapper) {
private AuthenticationAPIClient(Auth0 auth0, OkHttpClient client, Gson gson) {
this.auth0 = auth0;
this.client = client;
this.mapper = mapper;
this.gson = gson;
this.factory = new RequestFactory();
final Telemetry telemetry = auth0.getTelemetry();
if (telemetry != null) {
Expand Down Expand Up @@ -187,7 +189,7 @@ public AuthenticationRequest loginWithOAuthAccessToken(String token, String conn
.setAccessToken(token)
.asDictionary();

return factory.authenticationPOST(url, client, mapper)
return factory.authenticationPOST(url, client, gson)
.addAuthenticationParameters(parameters);
}

Expand Down Expand Up @@ -304,7 +306,7 @@ public DatabaseConnectionRequest<DatabaseUser> createUser(String email, String p
.setConnection(defaultDatabaseConnection)
.setClientId(getClientId())
.asDictionary();
final ParameterizableRequest<DatabaseUser> request = factory.POST(url, client, mapper, DatabaseUser.class)
final ParameterizableRequest<DatabaseUser> request = factory.POST(url, client, gson, DatabaseUser.class)
.addParameters(parameters);
return new DatabaseConnectionRequest<>(request);
}
Expand Down Expand Up @@ -413,7 +415,7 @@ public DatabaseConnectionRequest<Void> requestChangePassword(String email) {
.setClientId(getClientId())
.setConnection(defaultDatabaseConnection)
.asDictionary();
final ParameterizableRequest<Void> request = factory.POST(url, client, mapper)
final ParameterizableRequest<Void> request = factory.POST(url, client, gson)
.addParameters(parameters);
return new DatabaseConnectionRequest<>(request);
}
Expand Down Expand Up @@ -524,7 +526,7 @@ public Request<Void> unlink(String userId, String accessToken) {
.set(USER_ID_KEY, userId)
.asDictionary();

return factory.POST(url, client, mapper)
return factory.POST(url, client, gson)
.addParameters(parameters);
}

Expand Down Expand Up @@ -612,7 +614,7 @@ public ParameterizableRequest<Map<String, Object>> delegation() {
.setClientId(getClientId())
.setGrantType(ParameterBuilder.GRANT_TYPE_JWT)
.asDictionary();
return factory.rawPOST(url, client, mapper)
return factory.rawPOST(url, client, gson)
.addParameters(parameters);
}

Expand All @@ -626,7 +628,7 @@ protected <T> ParameterizableRequest<T> delegation(Class<T> clazz) {
.setGrantType(ParameterBuilder.GRANT_TYPE_JWT)
.asDictionary();

return factory.POST(url, client, mapper, clazz)
return factory.POST(url, client, gson, clazz)
.addParameters(parameters);
}

Expand All @@ -644,7 +646,7 @@ public ParameterizableRequest<Void> passwordless() {
final Map<String, Object> parameters = ParameterBuilder.newBuilder()
.setClientId(getClientId())
.asDictionary();
return factory.POST(url, client, mapper)
return factory.POST(url, client, gson)
.addParameters(parameters);
}

Expand All @@ -671,7 +673,7 @@ private AuthenticationRequest loginWithResourceOwner(Map<String, Object> paramet
.setConnection(defaultDatabaseConnection)
.addAll(parameters)
.asDictionary();
return factory.authenticationPOST(url, client, mapper)
return factory.authenticationPOST(url, client, gson)
.addAuthenticationParameters(requestParameters);
}

Expand All @@ -680,7 +682,7 @@ private ParameterizableRequest<UserProfile> profileRequest() {
.addPathSegment(TOKEN_INFO_PATH)
.build();

return factory.POST(url, client, mapper, UserProfile.class);
return factory.POST(url, client, gson, UserProfile.class);
}

/**
Expand All @@ -705,7 +707,13 @@ public AuthenticationRequest token(String authorizationCode, String codeVerifier
.addPathSegment(TOKEN_PATH)
.build();

return factory.authenticationPOST(url, client, mapper)
return factory.authenticationPOST(url, client, gson)
.addAuthenticationParameters(parameters);
}

static Gson buildGson() {
return new GsonBuilder()
.registerTypeAdapterFactory(new JsonRequiredTypeAdapterFactory())
.create();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,27 @@

package com.auth0.authentication.result;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import com.google.gson.annotations.SerializedName;

/**
* Holds the user's credentials returned by Auth0.
* <ul>
* <li><i>idToken</i>: Identity Token with user information</li>
* <li><i>accessToken</i>: Access Token for Auth0 API</li>
* <li><i>refreshToken</i>: Refresh Token that can be used to request new tokens without signing in again</li>
* <li><i>idToken</i>: Identity Token with user information</li>
* <li><i>accessToken</i>: Access Token for Auth0 API</li>
* <li><i>refreshToken</i>: Refresh Token that can be used to request new tokens without signing in again</li>
* </ul>
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class Credentials {

@SerializedName("id_token")
@JsonRequired
protected String idToken;
@SerializedName("access_token")
protected String accessToken;
@SerializedName("token_type")
protected String type;
@SerializedName("refresh_token")
protected String refreshToken;

protected Credentials(Credentials credentials) {
Expand All @@ -50,12 +54,10 @@ protected Credentials(Credentials credentials) {
refreshToken = credentials.refreshToken;
}

protected Credentials() { }
protected Credentials() {
}

public Credentials(@JsonProperty(value = "id_token", required = true) String idToken,
@JsonProperty(value = "access_token") String accessToken,
@JsonProperty(value = "token_type") String type,
@JsonProperty(value = "refresh_token") String refreshToken) {
public Credentials(String idToken, String accessToken, String type, String refreshToken) {
this.idToken = idToken;
this.accessToken = accessToken;
this.type = type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,25 @@

package com.auth0.authentication.result;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.SerializedName;

/**
* Auth0 user created in a Database connection.
*
* @see com.auth0.authentication.AuthenticationAPIClient#signUp(String, String)
* @see com.auth0.authentication.AuthenticationAPIClient#signUp(String, String, String)
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class DatabaseUser {

@SerializedName("email")
@JsonRequired
private final String email;
@SerializedName("username")
private final String username;
@SerializedName("email_verified")
private final boolean emailVerified;

public DatabaseUser(@JsonProperty(value = "email", required = true) String email,
@JsonProperty("username") String username,
@JsonProperty("email_verified") boolean emailVerified) {
public DatabaseUser(String email, String username, boolean emailVerified) {
this.email = email;
this.username = username;
this.emailVerified = emailVerified;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,23 @@

package com.auth0.authentication.result;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.SerializedName;

import static com.auth0.util.CheckHelper.checkArgument;

/**
* The result of a successful delegation to an Auth0 application that contains a new Auth0 'id_token'
* See <a href="https://auth0.com/docs/auth-api#!#post--delegation">delegation</a> docs
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class Delegation {
@SerializedName("id_token")
private final String idToken;
@SerializedName("token_type")
private final String type;
@SerializedName("expires_in")
private final Long expiresIn;

@JsonCreator
public Delegation(@JsonProperty(value = "id_token") String idToken,
@JsonProperty(value = "token_type") String type,
@JsonProperty(value = "expires_in") Long expiresIn) {
public Delegation(String idToken, String type, Long expiresIn) {
checkArgument(idToken != null, "id_token must be non-null");
checkArgument(type != null, "token_type must be non-null");
checkArgument(expiresIn != null, "expires_in must be non-null");
Expand All @@ -54,6 +51,7 @@ public Delegation(@JsonProperty(value = "id_token") String idToken,

/**
* Identity Token
*
* @return the 'id_token' value
*/
public String getIdToken() {
Expand All @@ -62,6 +60,7 @@ public String getIdToken() {

/**
* Token type
*
* @return the 'token_type' value
*/
public String getType() {
Expand All @@ -70,6 +69,7 @@ public String getType() {

/**
* Token expire time in milliseconds since January 1, 1970, 00:00:00 GMT
*
* @return the 'expires_in' value
*/
public Long getExpiresIn() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* JsonRequired.java
*
* Copyright (c) 2016 Auth0 (http://auth0.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package com.auth0.authentication.result;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonRequired {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.auth0.authentication.result;

import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.lang.reflect.Field;


public class JsonRequiredTypeAdapterFactory implements TypeAdapterFactory {

public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {

final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);

return new TypeAdapter<T>() {

public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}

public T read(JsonReader in) throws IOException {
T pojo = delegate.read(in);

Field[] fields = pojo.getClass().getDeclaredFields();
for (Field f : fields) {
if (f.getAnnotation(JsonRequired.class) != null) {
try {
f.setAccessible(true);
if (f.get(pojo) == null) {
throw new JsonParseException("Missing field in JSON: " + f.getName());
}
} catch (IllegalAccessException ex) {
throw new JsonParseException("Missing field in JSON: " + f.getName(), ex);
}
}
}
return pojo;
}
}.nullSafe();
}
}
Loading

0 comments on commit 6b6fa1f

Please sign in to comment.