Skip to content

Commit

Permalink
Add possibility to inject custom GsonBuilder
Browse files Browse the repository at this point in the history
Reverts openhab#1891

Fixes openhab#1888

Signed-off-by: Jacob Laursen <[email protected]>
  • Loading branch information
jlaur committed Apr 10, 2023
1 parent 643fe49 commit e4675a5
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonDeserializer;
import com.google.gson.GsonBuilder;

/**
* Implementation of OAuthClientService.
Expand Down Expand Up @@ -68,16 +68,19 @@ public class OAuthClientServiceImpl implements OAuthClientService {
private final String handle;
private final int tokenExpiresInSeconds;
private final HttpClientFactory httpClientFactory;
private final @Nullable GsonBuilder gsonBuilder;
private final List<AccessTokenRefreshListener> accessTokenRefreshListeners = new ArrayList<>();

private PersistedParams persistedParams = new PersistedParams();

private volatile boolean closed = false;

private OAuthClientServiceImpl(String handle, int tokenExpiresInSeconds, HttpClientFactory httpClientFactory) {
private OAuthClientServiceImpl(String handle, int tokenExpiresInSeconds, HttpClientFactory httpClientFactory,
@Nullable GsonBuilder gsonBuilder) {
this.handle = handle;
this.tokenExpiresInSeconds = tokenExpiresInSeconds;
this.httpClientFactory = httpClientFactory;
this.gsonBuilder = gsonBuilder;
}

/**
Expand All @@ -103,7 +106,7 @@ private OAuthClientServiceImpl(String handle, int tokenExpiresInSeconds, HttpCli
return null;
}
OAuthClientServiceImpl clientService = new OAuthClientServiceImpl(handle, tokenExpiresInSeconds,
httpClientFactory);
httpClientFactory, null);
clientService.storeHandler = storeHandler;
clientService.persistedParams = persistedParamsFromStore;

Expand All @@ -124,7 +127,7 @@ private OAuthClientServiceImpl(String handle, int tokenExpiresInSeconds, HttpCli
static OAuthClientServiceImpl createInstance(String handle, OAuthStoreHandler storeHandler,
HttpClientFactory httpClientFactory, PersistedParams params) {
OAuthClientServiceImpl clientService = new OAuthClientServiceImpl(handle, params.tokenExpiresInSeconds,
httpClientFactory);
httpClientFactory, null);

clientService.storeHandler = storeHandler;
clientService.persistedParams = params;
Expand Down Expand Up @@ -153,7 +156,9 @@ public String getAuthorizationUrl(@Nullable String redirectURI, @Nullable String
throw new OAuthException("Missing client ID");
}

OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
GsonBuilder gsonBuilder = this.gsonBuilder;
OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory)
: new OAuthConnector(httpClientFactory, gsonBuilder);
return connector.getAuthorizationUrl(authorizationUrl, clientId, redirectURI, persistedParams.state,
scopeToUse);
}
Expand Down Expand Up @@ -207,7 +212,9 @@ public AccessTokenResponse getAccessTokenResponseByAuthorizationCode(String auth
throw new OAuthException("Missing client ID");
}

OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
GsonBuilder gsonBuilder = this.gsonBuilder;
OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory)
: new OAuthConnector(httpClientFactory, gsonBuilder);
AccessTokenResponse accessTokenResponse = connector.grantTypeAuthorizationCode(tokenUrl, authorizationCode,
clientId, persistedParams.clientSecret, redirectURI,
Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
Expand Down Expand Up @@ -239,7 +246,9 @@ public AccessTokenResponse getAccessTokenByResourceOwnerPasswordCredentials(Stri
throw new OAuthException("Missing token url");
}

OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
GsonBuilder gsonBuilder = this.gsonBuilder;
OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory)
: new OAuthConnector(httpClientFactory, gsonBuilder);
AccessTokenResponse accessTokenResponse = connector.grantTypePassword(tokenUrl, username, password,
persistedParams.clientId, persistedParams.clientSecret, scope,
Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
Expand All @@ -264,7 +273,9 @@ public AccessTokenResponse getAccessTokenByClientCredentials(@Nullable String sc
throw new OAuthException("Missing client ID");
}

OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
GsonBuilder gsonBuilder = this.gsonBuilder;
OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory)
: new OAuthConnector(httpClientFactory, gsonBuilder);
// depending on usage, cannot guarantee every parameter is not null at the beginning
AccessTokenResponse accessTokenResponse = connector.grantTypeClientCredentials(tokenUrl, clientId,
persistedParams.clientSecret, scope, Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
Expand Down Expand Up @@ -298,7 +309,9 @@ public AccessTokenResponse refreshToken() throws OAuthException, IOException, OA
throw new OAuthException("tokenUrl is required but null");
}

OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
GsonBuilder gsonBuilder = this.gsonBuilder;
OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory)
: new OAuthConnector(httpClientFactory, gsonBuilder);
AccessTokenResponse accessTokenResponse = connector.grantTypeRefreshToken(tokenUrl,
lastAccessToken.getRefreshToken(), persistedParams.clientId, persistedParams.clientSecret,
persistedParams.scope, Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
Expand Down Expand Up @@ -400,10 +413,9 @@ private String createNewState() {
}

@Override
public <T extends JsonDeserializer<?>> OAuthClientService withDeserializer(Class<T> deserializerClass) {
public OAuthClientService withGsonBuilder(GsonBuilder gsonBuilder) {
OAuthClientServiceImpl clientService = new OAuthClientServiceImpl(handle, persistedParams.tokenExpiresInSeconds,
httpClientFactory);
persistedParams.deserializerClassName = deserializerClass.getName();
httpClientFactory, gsonBuilder);
clientService.persistedParams = persistedParams;
clientService.storeHandler = storeHandler;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import static org.openhab.core.auth.oauth2client.internal.Keyword.*;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
Expand Down Expand Up @@ -67,29 +66,20 @@ public class OAuthConnector {
private final Logger logger = LoggerFactory.getLogger(OAuthConnector.class);
private final Gson gson;

public OAuthConnector(HttpClientFactory httpClientFactory, @Nullable String deserializerClassName) {
public OAuthConnector(HttpClientFactory httpClientFactory) {
this(httpClientFactory, new GsonBuilder());
}

public OAuthConnector(HttpClientFactory httpClientFactory, GsonBuilder gsonBuilder) {
this.httpClientFactory = httpClientFactory;
GsonBuilder gsonBuilder = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
gson = gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(Instant.class, (JsonDeserializer<Instant>) (json, typeOfT, context) -> {
try {
return Instant.parse(json.getAsString());
} catch (DateTimeParseException e) {
return LocalDateTime.parse(json.getAsString()).atZone(ZoneId.systemDefault()).toInstant();
}
});

if (deserializerClassName != null) {
try {
Class<?> deserializerClass = Class.forName(deserializerClassName);
gsonBuilder = gsonBuilder.registerTypeAdapter(AccessTokenResponse.class,
deserializerClass.getConstructor().newInstance());
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException
| ClassNotFoundException e) {
logger.error("Unable to construct custom deserializer '{}'", deserializerClassName, e);
}
}
gson = gsonBuilder.create();
}).create();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ class PersistedParams {
String state;
String redirectUri;
int tokenExpiresInSeconds = 60;
@Nullable
String deserializerClassName;

/**
* Default constructor needed for json serialization.
Expand All @@ -59,7 +57,6 @@ public PersistedParams() {
* of the access tokens. This allows the access token to expire earlier than the
* official stated expiry time; thus prevents the caller obtaining a valid token at the time of invoke,
* only to find the token immediately expired.
* @param deserializerClass (optional) if a specific deserializer is needed
*/
public PersistedParams(String handle, String tokenUrl, String authorizationUrl, String clientId,
String clientSecret, String scope, Boolean supportsBasicAuth, int tokenExpiresInSeconds,
Expand All @@ -72,7 +69,6 @@ public PersistedParams(String handle, String tokenUrl, String authorizationUrl,
this.scope = scope;
this.supportsBasicAuth = supportsBasicAuth;
this.tokenExpiresInSeconds = tokenExpiresInSeconds;
this.deserializerClassName = deserializerClassName;
}

@Override
Expand All @@ -89,7 +85,6 @@ public int hashCode() {
result = prime * result + ((supportsBasicAuth == null) ? 0 : supportsBasicAuth.hashCode());
result = prime * result + tokenExpiresInSeconds;
result = prime * result + ((tokenUrl == null) ? 0 : tokenUrl.hashCode());
result = prime * result + ((deserializerClassName != null) ? deserializerClassName.hashCode() : 0);
return result;
}

Expand Down Expand Up @@ -168,13 +163,6 @@ public boolean equals(@Nullable Object obj) {
} else if (!tokenUrl.equals(other.tokenUrl)) {
return false;
}
if (deserializerClassName == null) {
if (other.deserializerClassName != null) {
return false;
}
} else if (deserializerClassName != null && !deserializerClassName.equals(other.deserializerClassName)) {
return false;
}

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

import com.google.gson.JsonDeserializer;
import com.google.gson.GsonBuilder;

/**
* This is the service factory to produce an OAuth2 service client that authenticates using OAUTH2.
Expand Down Expand Up @@ -291,10 +291,10 @@ AccessTokenResponse getAccessTokenByImplicit(@Nullable String redirectURI, @Null
boolean removeAccessTokenRefreshListener(AccessTokenRefreshListener listener);

/**
* Adds a personalized deserializer to a given oauth service.
* Adds a custom GsonBuilder to be used with a given OAuth service.
*
* @param deserializeClass the deserializer class that should be used to deserialize AccessTokenResponse
* @return the oauth service
* @param gsonBuilder the custom GsonBuilder instance
* @return the OAuth service
*/
<T extends JsonDeserializer<?>> OAuthClientService withDeserializer(Class<T> deserializerClass);
OAuthClientService withGsonBuilder(GsonBuilder gsonBuilder);
}

0 comments on commit e4675a5

Please sign in to comment.