Repository: SAP/cloud-security-xsuaa-integration
Pull request #131 (2019-09-04 15:25:43)

Removed some spring dependencies
Plus minor refactorings


Patch:
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfiguration.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfiguration.java
index 1ce9d491..27549f76 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfiguration.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfiguration.java
@@ -1,9 +1,7 @@
 package com.sap.cloud.security.xsuaa.autoconfiguration;
 
 import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.client.ClientCredentials;
-import com.sap.cloud.security.xsuaa.client.OAuth2ServiceEndpointsProvider;
-import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
+import com.sap.cloud.security.xsuaa.client.*;
 import com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlows;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -56,6 +54,7 @@ public class XsuaaTokenFlowAutoConfiguration {
 		OAuth2ServiceEndpointsProvider endpointsProvider = new XsuaaDefaultEndpoints(serviceConfiguration.getUaaUrl());
 		ClientCredentials clientCredentials = new ClientCredentials(serviceConfiguration.getClientId(),
 				serviceConfiguration.getClientSecret());
-		return new XsuaaTokenFlows(restOperations, endpointsProvider, clientCredentials);
+		OAuth2TokenService oAuth2TokenService = new XsuaaOAuth2TokenService(restOperations);
+		return new XsuaaTokenFlows(oAuth2TokenService, endpointsProvider, clientCredentials);
 	}
 }
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaToken.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaToken.java
index 01ebb736..86f62bc3 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaToken.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaToken.java
@@ -17,7 +17,9 @@ import java.util.List;
 import java.util.Map;
 
 import com.sap.cloud.security.xsuaa.client.ClientCredentials;
+import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
 import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
+import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
 import com.sap.cloud.security.xsuaa.tokenflows.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -241,8 +243,10 @@ public class XsuaaToken extends Jwt implements Token {
 				"");
 
 		// initialize token flows api
-		xsuaaTokenFlows = new XsuaaTokenFlows(restOperations, new XsuaaDefaultEndpoints(baseUrl), new ClientCredentials(
-				tokenRequest.getClientId(), tokenRequest.getClientSecret()));
+		OAuth2TokenService oAuth2TokenService = new XsuaaOAuth2TokenService(restOperations);
+		xsuaaTokenFlows = new XsuaaTokenFlows(oAuth2TokenService, new XsuaaDefaultEndpoints(baseUrl),
+				new ClientCredentials(
+						tokenRequest.getClientId(), tokenRequest.getClientSecret()));
 
 		switch (tokenRequest.getType()) {
 		case XSTokenRequest.TYPE_USER_TOKEN:
diff --git a/token-client/README.md b/token-client/README.md
index eabb0a66..afea3e9d 100644
--- a/token-client/README.md
+++ b/token-client/README.md
@@ -43,7 +43,7 @@ Then, xsuaa integration libraries auto-configures beans, that are required to in
 
 Auto-configuration class | Description
 ---- | --------
-[XsuaaAutoConfiguration](/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfiguration.java) | Adds `xsuaa.*` properties to Spring's Environment. The properties are by default parsed from `VCAP_SERVICES` system environment variables and can be overwritten by properties such as `xsuaa.url` e.g. for testing purposes. Furthermore it exposes a `XsuaaServiceConfiguration` bean that can be used to access xsuaa service information.  Alternatively you can access them with `@Value` annotation e.g. `@Value("${xsuaa.url:}") String xsuaaBaseUrl`. As of version `1.7.0` it creates a default [`RestTemplate`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestOperations.html) bean that serves as Rest client to perform HTTP requests to the XSUAA server. **It is recommended to overwrite this default and configuring it with the HTTP client of your choice.**
+[XsuaaAutoConfiguration](/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfiguration.java) | Adds `xsuaa.*` properties to Spring's Environment. The properties are by default parsed from `VCAP_SERVICES` system environment variables and can be overwritten by properties such as `xsuaa.url` e.g. for testing purposes. Furthermore it exposes a `XsuaaServiceConfiguration` bean that can be used to access xsuaa service information.  Alternatively you can access them with `@Value` annotation e.g. `@Value("${xsuaa.url:}") String xsuaaBaseUrl`. As of version `1.7.0` it creates a default [`RestTemplate`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestOperations.html) bean that serves as Rest client that is used inside a default `OAuth2TokenService` to perform HTTP requests to the XSUAA server. **It is recommended to overwrite this default and configuring it with the HTTP client of your choice.**
 [XsuaaTokenFlowAutoConfiguration](/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfiguration.java) | Configures a `XsuaaTokenFlows` bean with a `RestOperations` and `XsuaaServiceConfiguration` bean to fetch the XSUAA service binding information.
 
 You can gradually replace auto-configurations as explained [here](https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html).
diff --git a/token-client/pom.xml b/token-client/pom.xml
index b94ab30d..714532a6 100644
--- a/token-client/pom.xml
+++ b/token-client/pom.xml
@@ -41,6 +41,11 @@
 			<artifactId>spring-security-jwt</artifactId>
 			<version>1.0.9.RELEASE</version>
 		</dependency>
+		<dependency>
+			<groupId>com.google.code.findbugs</groupId>
+			<artifactId>jsr305</artifactId>
+			<version>3.0.2</version>
+		</dependency>
 
 
 		<dependency>
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/Assertions.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/Assertions.java
new file mode 100644
index 00000000..b3b29efd
--- /dev/null
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/Assertions.java
@@ -0,0 +1,9 @@
+package com.sap.cloud.security.xsuaa;
+
+public class Assertions {
+	public static void assertNotNull(Object object, String message) {
+		if (object == null) {
+			throw new IllegalArgumentException(message);
+		}
+	}
+}
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/ClientCredentials.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/ClientCredentials.java
index e1abb055..325678b2 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/ClientCredentials.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/ClientCredentials.java
@@ -1,9 +1,9 @@
 package com.sap.cloud.security.xsuaa.client;
 
-import java.util.Objects;
+import com.sap.cloud.security.xsuaa.Assertions;
 
-import org.springframework.lang.NonNull;
-import org.springframework.util.Assert;
+import javax.annotation.Nonnull;
+import java.util.Objects;
 
 public class ClientCredentials {
 
@@ -18,9 +18,9 @@ public class ClientCredentials {
 	 * @param clientSecret
 	 *            - the secret of the OAuth 2.0 client requesting the token.
 	 */
-	public ClientCredentials(@NonNull String clientId, @NonNull String clientSecret) {
-		Assert.notNull(clientId, "clientId is required");
-		Assert.notNull(clientSecret, "clientSecret is required");
+	public ClientCredentials(@Nonnull String clientId, @Nonnull String clientSecret) {
+		Assertions.assertNotNull(clientId, "clientId is required");
+		Assertions.assertNotNull(clientSecret, "clientSecret is required");
 		this.clientId = clientId;
 		this.clientSecret = clientSecret;
 	}
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenResponse.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenResponse.java
index 5eb298a8..ab626126 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenResponse.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenResponse.java
@@ -1,10 +1,9 @@
 package com.sap.cloud.security.xsuaa.client;
 
+import javax.annotation.Nullable;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
 
-import org.springframework.lang.Nullable;
-
 public class OAuth2TokenResponse {
 	private String refreshToken;
 	private String accessToken;
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java
index 37e4872f..00c8421e 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java
@@ -1,10 +1,9 @@
 package com.sap.cloud.security.xsuaa.client;
 
+import javax.annotation.Nullable;
 import java.net.URI;
 import java.util.Map;
 
-import org.springframework.lang.Nullable;
-
 /**
  * Retrieves OAuth2 Access Tokens as documented here:
  * https://docs.cloudfoundry.org/api/uaa/version/4.31.0/index.html#token
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java
index 3b8fdd11..c3ec8537 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java
@@ -35,7 +35,7 @@ import org.springframework.web.util.UriComponentsBuilder;
 
 public class XsuaaOAuth2TokenService implements OAuth2TokenService {
 
-	private RestOperations restOperations;
+	private final RestOperations restOperations;
 	private static Logger logger = LoggerFactory.getLogger(XsuaaOAuth2TokenService.class);
 
 	public XsuaaOAuth2TokenService(@NonNull RestOperations restOperations) {
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/ClientCredentialsTokenFlow.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/ClientCredentialsTokenFlow.java
index cc3e0f35..b0e27093 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/ClientCredentialsTokenFlow.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/ClientCredentialsTokenFlow.java
@@ -1,13 +1,11 @@
 package com.sap.cloud.security.xsuaa.tokenflows;
 
+import static com.sap.cloud.security.xsuaa.Assertions.assertNotNull;
 import static com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlowsUtils.buildAuthorities;
 
 import java.util.HashMap;
 import java.util.Map;
 
-import org.springframework.lang.Nullable;
-import org.springframework.util.Assert;
-
 import com.sap.cloud.security.xsuaa.client.ClientCredentials;
 import com.sap.cloud.security.xsuaa.client.OAuth2TokenResponse;
 import com.sap.cloud.security.xsuaa.client.OAuth2ServiceEndpointsProvider;
@@ -15,6 +13,8 @@ import com.sap.cloud.security.xsuaa.client.OAuth2ServiceException;
 import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
 import com.sap.xsa.security.container.XSTokenRequest;
 
+import javax.annotation.Nullable;
+
 /**
  * A client credentials flow builder class. Applications retrieve an instance of
  * this builder from {@link XsuaaTokenFlows} and then create the flow request
@@ -40,9 +40,9 @@ public class ClientCredentialsTokenFlow {
 	 */
 	ClientCredentialsTokenFlow(OAuth2TokenService tokenService, OAuth2ServiceEndpointsProvider endpointsProvider,
 			ClientCredentials clientCredentials) {
-		Assert.notNull(tokenService, "OAuth2TokenService must not be null.");
-		Assert.notNull(endpointsProvider, "OAuth2ServiceEndpointsProvider must not be null.");
-		Assert.notNull(clientCredentials, "ClientCredentials must not be null.");
+		assertNotNull(tokenService, "OAuth2TokenService must not be null.");
+		assertNotNull(endpointsProvider, "OAuth2ServiceEndpointsProvider must not be null.");
+		assertNotNull(clientCredentials, "ClientCredentials must not be null.");
 
 		this.tokenService = tokenService;
 		this.request = new XsuaaTokenFlowRequest(endpointsProvider.getTokenEndpoint());
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/RefreshTokenFlow.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/RefreshTokenFlow.java
index edc317b5..4176f11a 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/RefreshTokenFlow.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/RefreshTokenFlow.java
@@ -1,7 +1,5 @@
 package com.sap.cloud.security.xsuaa.tokenflows;
 
-import org.springframework.util.Assert;
-
 import com.sap.cloud.security.xsuaa.client.ClientCredentials;
 import com.sap.cloud.security.xsuaa.client.OAuth2TokenResponse;
 import com.sap.cloud.security.xsuaa.client.OAuth2ServiceEndpointsProvider;
@@ -9,6 +7,8 @@ import com.sap.cloud.security.xsuaa.client.OAuth2ServiceException;
 import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
 import com.sap.xsa.security.container.XSTokenRequest;
 
+import static com.sap.cloud.security.xsuaa.Assertions.assertNotNull;
+
 /**
  * A refresh token flow builder. <br>
  * Applications can use this flow exchange a given refresh token for a
@@ -33,9 +33,9 @@ public class RefreshTokenFlow {
 	 */
 	RefreshTokenFlow(OAuth2TokenService tokenService, OAuth2ServiceEndpointsProvider endpointsProvider,
 			ClientCredentials clientCredentials) {
-		Assert.notNull(tokenService, "OAuth2TokenService must not be null.");
-		Assert.notNull(endpointsProvider, "OAuth2ServiceEndpointsProvider must not be null.");
-		Assert.notNull(clientCredentials, "ClientCredentials must not be null.");
+		assertNotNull(tokenService, "OAuth2TokenService must not be null.");
+		assertNotNull(endpointsProvider, "OAuth2ServiceEndpointsProvider must not be null.");
+		assertNotNull(clientCredentials, "ClientCredentials must not be null.");
 
 		this.tokenService = tokenService;
 		this.request = new XsuaaTokenFlowRequest(endpointsProvider.getTokenEndpoint());
@@ -63,7 +63,7 @@ public class RefreshTokenFlow {
 	 * @return this builder object.
 	 */
 	public RefreshTokenFlow refreshToken(String refreshToken) {
-		Assert.notNull(refreshToken, "RefreshToken must not be null.");
+		assertNotNull(refreshToken, "RefreshToken must not be null.");
 		this.refreshToken = refreshToken;
 		return this;
 	}
@@ -73,14 +73,16 @@ public class RefreshTokenFlow {
 	 * 
 	 * @return the refreshed OAuth access token returned by XSUAA or an exception in
 	 *         case the token could not be refreshed.
-	 * @throws IllegalArgumentException
+	 * @throws IllegalStateException
 	 *             - in case not all mandatory fields of the token flow request have
 	 *             been set.
+	 * @throws IllegalArgumentException
+	 *             - in case the refresh token flow request is not valid.
 	 * @throws TokenFlowException
 	 *             - in case of an error during the flow, or when the token cannot
 	 *             be refreshed.
 	 */
-	public OAuth2TokenResponse execute() throws IllegalArgumentException, TokenFlowException {
+	public OAuth2TokenResponse execute() throws IllegalStateException, IllegalArgumentException, TokenFlowException {
 		checkRequest(request);
 
 		return refreshToken(refreshToken, request);
@@ -92,13 +94,15 @@ public class RefreshTokenFlow {
 	 * 
 	 * @param request
 	 *            - the request to check.
-	 * @throws IllegalArgumentException
-	 *             in case not all mandatory fields of the token flow request have
+	 * @throws IllegalStateException
+	 *             - in case not all mandatory fields of the token flow request have
 	 *             been set.
+	 * @throws IllegalArgumentException
+	 *             - in case the refresh token flow request is not valid.
 	 */
-	private void checkRequest(XSTokenRequest request) throws IllegalArgumentException {
+	private void checkRequest(XSTokenRequest request) throws IllegalStateException, IllegalArgumentException {
 		if (refreshToken == null) {
-			throw new IllegalArgumentException(
+			throw new IllegalStateException(
 					"Refresh token not set. Make sure to have called the refreshToken() method on RefreshTokenFlow builder.");
 		}
 
@@ -118,7 +122,7 @@ public class RefreshTokenFlow {
 	 * @return the encoded OAuth access token received in exchange for the refresh
 	 *         token.
 	 * @throws TokenFlowException
-	 *             in case of an error in the flow.
+	 *             - in case of an error in the flow.
 	 */
 	private OAuth2TokenResponse refreshToken(String refreshToken, XsuaaTokenFlowRequest request)
 			throws TokenFlowException {
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlow.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlow.java
index 99e612aa..59a4fa66 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlow.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlow.java
@@ -10,7 +10,7 @@ import java.util.Map;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
-import org.springframework.util.Assert;
+import static com.sap.cloud.security.xsuaa.Assertions.assertNotNull;
 
 import com.sap.cloud.security.xsuaa.client.ClientCredentials;
 import com.sap.cloud.security.xsuaa.client.OAuth2TokenResponse;
@@ -51,10 +51,10 @@ public class UserTokenFlow {
 	 */
 	UserTokenFlow(OAuth2TokenService tokenService, RefreshTokenFlow refreshTokenFlow,
 			OAuth2ServiceEndpointsProvider endpointsProvider, ClientCredentials clientCredentials) {
-		Assert.notNull(tokenService, "OAuth2TokenService must not be null.");
-		Assert.notNull(refreshTokenFlow, "RefreshTokenFlow must not be null.");
-		Assert.notNull(endpointsProvider, "OAuth2ServiceEndpointsProvider must not be null.");
-		Assert.notNull(clientCredentials, "ClientCredentials must not be null.");
+		assertNotNull(tokenService, "OAuth2TokenService must not be null.");
+		assertNotNull(refreshTokenFlow, "RefreshTokenFlow must not be null.");
+		assertNotNull(endpointsProvider, "OAuth2ServiceEndpointsProvider must not be null.");
+		assertNotNull(clientCredentials, "ClientCredentials must not be null.");
 
 		this.tokenService = tokenService;
 		this.refreshTokenFlow = refreshTokenFlow;
@@ -71,7 +71,7 @@ public class UserTokenFlow {
 	 * @return this builder object.
 	 */
 	public UserTokenFlow token(String token) {
-		Assert.notNull(token, "Token must not be null.");
+		assertNotNull(token, "Token must not be null.");
 		this.token = token;
 		return this;
 	}
@@ -109,7 +109,7 @@ public class UserTokenFlow {
 	 * Note, that in a standard flow, only the refresh token would be returned.
 	 *
 	 * @return the JWT instance returned by XSUAA.
-	 * @throws IllegalArgumentException
+	 * @throws IllegalStateException
 	 *             - in case not all mandatory fields of the token flow request have
 	 *             been set.
 	 * @throws TokenFlowException
@@ -128,18 +128,21 @@ public class UserTokenFlow {
 	 * @param request
 	 *            - the token flow request.
 	 * @throws IllegalArgumentException
-	 *             in case not all mandatory fields of the token flow request have
+	 *             - in case not all mandatory fields of the token flow request have
 	 *             been set.
+	 * @throws IllegalStateException
+	 *             - in case the user token has not been set or does not include
+	 *             scope 'uaa.user'
 	 */
 	private void checkRequest(XSTokenRequest request) throws IllegalArgumentException {
 		if (token == null) {
-			throw new IllegalArgumentException(
+			throw new IllegalStateException(
 					"User token not set. Make sure to have called the token() method on UserTokenFlow builder.");
 		}
 
 		boolean isUserToken = hasScope(token, UAA_USER_SCOPE);
 		if (!isUserToken) {
-			throw new IllegalArgumentException(
+			throw new IllegalStateException(
 					"JWT token does not include scope 'uaa.user'. Only user tokens can be exchanged for another user token.");
 		}
 
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowRequest.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowRequest.java
index 7a242cf9..e3d7a4e6 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowRequest.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowRequest.java
@@ -1,14 +1,14 @@
 package com.sap.cloud.security.xsuaa.tokenflows;
 
+import com.sap.xsa.security.container.XSTokenRequest;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import java.net.URI;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.springframework.lang.NonNull;
-import org.springframework.lang.Nullable;
-import org.springframework.util.Assert;
-
-import com.sap.xsa.security.container.XSTokenRequest;
+import static com.sap.cloud.security.xsuaa.Assertions.assertNotNull;
 
 /**
  * An internal token exchange request capturing data by the token flow builders
@@ -28,8 +28,8 @@ class XsuaaTokenFlowRequest implements XSTokenRequest {
 	 * @param tokenServiceEndpoint
 	 *            - the URI of the OAuth server token endpoint.
 	 */
-	XsuaaTokenFlowRequest(@NonNull URI tokenServiceEndpoint) {
-		Assert.notNull(tokenServiceEndpoint, "tokenServiceEndpoint is required");
+	XsuaaTokenFlowRequest(@Nonnull URI tokenServiceEndpoint) {
+		assertNotNull(tokenServiceEndpoint, "tokenServiceEndpoint is required");
 		this.tokenServiceEndpoint = tokenServiceEndpoint;
 	}
 
@@ -44,7 +44,7 @@ class XsuaaTokenFlowRequest implements XSTokenRequest {
 	}
 
 	public XSTokenRequest setClientId(String clientId) {
-		Assert.notNull(clientId, "OAuth 2.0 client ID must not be null.");
+		assertNotNull(clientId, "OAuth 2.0 client ID must not be null.");
 		this.clientId = clientId;
 		return this;
 	}
@@ -60,7 +60,7 @@ class XsuaaTokenFlowRequest implements XSTokenRequest {
 	}
 
 	public XSTokenRequest setClientSecret(String clientSecret) {
-		Assert.notNull(clientSecret, "OAuth 2.0 client secret must not be null.");
+		assertNotNull(clientSecret, "OAuth 2.0 client secret must not be null.");
 		this.clientSecret = clientSecret;
 		return this;
 	}
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlows.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlows.java
index d8add940..0a3259a3 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlows.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlows.java
@@ -2,13 +2,11 @@ package com.sap.cloud.security.xsuaa.tokenflows;
 
 import java.io.Serializable;
 
-import org.springframework.util.Assert;
-import org.springframework.web.client.RestOperations;
-
 import com.sap.cloud.security.xsuaa.client.ClientCredentials;
 import com.sap.cloud.security.xsuaa.client.OAuth2ServiceEndpointsProvider;
 import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
-import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
+
+import static com.sap.cloud.security.xsuaa.Assertions.assertNotNull;
 
 /**
  * A bean that can be {@code @Autowired} by applications to get access to token
@@ -22,15 +20,15 @@ public class XsuaaTokenFlows implements Serializable {
 	private static final long serialVersionUID = 2403173341950251507L;
 
 	private final ClientCredentials clientCredentials;
-	private RestOperations restOperations;
-	private OAuth2ServiceEndpointsProvider endpointsProvider;
+	private final OAuth2TokenService oAuth2TokenService;
+	private final OAuth2ServiceEndpointsProvider endpointsProvider;
 
 	/**
 	 * Create a new instance of this bean with the given RestTemplate. Applications
 	 * should {@code @Autowire} instances of this bean.
 	 * 
-	 * @param restOperations
-	 *            the RestTemplate instance that will be used to send the token
+	 * @param oAuth2TokenService
+	 *            the OAuth2TokenService that will be used to send the token
 	 *            exchange request.
 	 * @param endpointsProvider
 	 *            the endpoint provider that serves the token endpoint.
@@ -51,13 +49,13 @@ public class XsuaaTokenFlows implements Serializable {
 	 * }
 	 *            </pre>
 	 */
-	public XsuaaTokenFlows(RestOperations restOperations,
+	public XsuaaTokenFlows(OAuth2TokenService oAuth2TokenService,
 			OAuth2ServiceEndpointsProvider endpointsProvider, ClientCredentials clientCredentials) {
-		Assert.notNull(restOperations, "RestOperations must not be null.");
-		Assert.notNull(endpointsProvider, "OAuth2ServiceEndpointsProvider must not be null.");
-		Assert.notNull(clientCredentials, "ClientCredentials must not be null.");
+		assertNotNull(oAuth2TokenService, "OAuth2TokenService must not be null.");
+		assertNotNull(endpointsProvider, "OAuth2ServiceEndpointsProvider must not be null");
+		assertNotNull(clientCredentials, "ClientCredentials must not be null.");
 
-		this.restOperations = restOperations;
+		this.oAuth2TokenService = oAuth2TokenService;
 		this.endpointsProvider = endpointsProvider;
 		this.clientCredentials = clientCredentials;
 	}
@@ -72,10 +70,10 @@ public class XsuaaTokenFlows implements Serializable {
 	 * @return the {@link UserTokenFlow} builder object.
 	 */
 	public UserTokenFlow userTokenFlow() {
-		OAuth2TokenService tokenService = initializeTokenService();
-		RefreshTokenFlow refreshTokenFlow = new RefreshTokenFlow(tokenService, endpointsProvider, clientCredentials);
+		RefreshTokenFlow refreshTokenFlow = new RefreshTokenFlow(oAuth2TokenService, endpointsProvider,
+				clientCredentials);
 
-		return new UserTokenFlow(tokenService, refreshTokenFlow, endpointsProvider, clientCredentials);
+		return new UserTokenFlow(oAuth2TokenService, refreshTokenFlow, endpointsProvider, clientCredentials);
 	}
 
 	/**
@@ -86,7 +84,7 @@ public class XsuaaTokenFlows implements Serializable {
 	 * @return the {@link ClientCredentialsTokenFlow} builder object.
 	 */
 	public ClientCredentialsTokenFlow clientCredentialsTokenFlow() {
-		return new ClientCredentialsTokenFlow(initializeTokenService(), endpointsProvider, clientCredentials);
+		return new ClientCredentialsTokenFlow(oAuth2TokenService, endpointsProvider, clientCredentials);
 	}
 
 	/**
@@ -97,10 +95,7 @@ public class XsuaaTokenFlows implements Serializable {
 	 * @return the {@link ClientCredentialsTokenFlow} builder object.
 	 */
 	public RefreshTokenFlow refreshTokenFlow() {
-		return new RefreshTokenFlow(initializeTokenService(), endpointsProvider, clientCredentials);
+		return new RefreshTokenFlow(oAuth2TokenService, endpointsProvider, clientCredentials);
 	}
 
-	OAuth2TokenService initializeTokenService() {
-		return new XsuaaOAuth2TokenService(restOperations);
-	}
 }


Test patch:
diff --git a/spring-xsuaa-it/src/main/java/testservice/api/v1/TestController.java b/spring-xsuaa-it/src/main/java/testservice/api/v1/TestController.java
index d9edcefc..270cb9e4 100644
--- a/spring-xsuaa-it/src/main/java/testservice/api/v1/TestController.java
+++ b/spring-xsuaa-it/src/main/java/testservice/api/v1/TestController.java
@@ -23,6 +23,7 @@ import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
 import com.sap.cloud.security.xsuaa.client.ClientCredentials;
 import com.sap.cloud.security.xsuaa.client.OAuth2TokenResponse;
 import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
+import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
 import com.sap.cloud.security.xsuaa.token.Token;
 import com.sap.cloud.security.xsuaa.tokenflows.ClientCredentialsTokenFlow;
 import com.sap.cloud.security.xsuaa.tokenflows.TokenFlowException;
@@ -99,7 +100,7 @@ public class TestController {
 		azMape.put("a", "b");
 		azMape.put("c", "d");
 
-		XsuaaTokenFlows tokenFlows = new XsuaaTokenFlows(new RestTemplate(),
+		XsuaaTokenFlows tokenFlows = new XsuaaTokenFlows(new XsuaaOAuth2TokenService(new RestTemplate()),
 				new XsuaaDefaultEndpoints(serviceConfiguration.getUaaUrl()), new ClientCredentials("c1", "s1"));
 		ClientCredentialsTokenFlow ccTokenFlow = tokenFlows.clientCredentialsTokenFlow().attributes(azMape)
 				.subdomain(token.getSubdomain());
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfigurationTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfigurationTest.java
index 5a30f296..7f757305 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfigurationTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfigurationTest.java
@@ -4,6 +4,7 @@ import com.sap.cloud.security.xsuaa.DummyXsuaaServiceConfiguration;
 import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
 import com.sap.cloud.security.xsuaa.client.ClientCredentials;
 import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
+import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
 import com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlows;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -90,7 +91,7 @@ public class XsuaaTokenFlowAutoConfigurationTest {
 		@Bean
 		public XsuaaTokenFlows userDefinedXsuaaTokenFlows(RestOperations restOperations,
 				XsuaaServiceConfiguration serviceConfiguration) {
-			return new XsuaaTokenFlows(restOperations,
+			return new XsuaaTokenFlows(new XsuaaOAuth2TokenService(restOperations),
 					new XsuaaDefaultEndpoints(serviceConfiguration.getUaaUrl()), new ClientCredentials("id", "secret"));
 		}
 	}
diff --git a/token-client/src/test/java/com/sap/cloud/security/xsuaa/AssertionsTest.java b/token-client/src/test/java/com/sap/cloud/security/xsuaa/AssertionsTest.java
new file mode 100644
index 00000000..31973096
--- /dev/null
+++ b/token-client/src/test/java/com/sap/cloud/security/xsuaa/AssertionsTest.java
@@ -0,0 +1,21 @@
+package com.sap.cloud.security.xsuaa;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class AssertionsTest {
+
+	@Test
+	public void assertNotNull_throwsIllegalArgumentExceptionContainingMessage() {
+		String message = "A message";
+		assertThatThrownBy(() -> {
+			Assertions.assertNotNull(null, message);
+		}).isInstanceOf(IllegalArgumentException.class).hasMessage(message);
+	}
+
+	@Test
+	public void assertNotNull_doesNotThrow() {
+		Assertions.assertNotNull(new Object(), "Should not be thrown");
+	}
+}
diff --git a/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/RefreshTokenFlowTest.java b/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/RefreshTokenFlowTest.java
index 81c3913a..58acaa7f 100644
--- a/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/RefreshTokenFlowTest.java
+++ b/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/RefreshTokenFlowTest.java
@@ -60,7 +60,7 @@ public class RefreshTokenFlowTest {
 	public void execute_throwsIfMandatoryFieldsNotSet() {
 		assertThatThrownBy(() -> {
 			cut.execute();
-		}).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("Refresh token not set");
+		}).isInstanceOf(IllegalStateException.class).hasMessageContaining("Refresh token not set");
 	}
 
 	@Test
diff --git a/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlowTest.java b/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlowTest.java
index 31a7de41..a61700fd 100644
--- a/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlowTest.java
+++ b/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlowTest.java
@@ -11,7 +11,6 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -89,11 +88,11 @@ public class UserTokenFlowTest {
 	public void execute_throwsIfMandatoryFieldsNotSet() {
 		assertThatThrownBy(() -> {
 			cut.execute();
-		}).isInstanceOf(IllegalArgumentException.class);
+		}).isInstanceOf(IllegalStateException.class);
 
 		assertThatThrownBy(() -> {
 			cut.execute();
-		}).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("User token not set");
+		}).isInstanceOf(IllegalStateException.class).hasMessageContaining("User token not set");
 	}
 
 	@Test
@@ -103,7 +102,7 @@ public class UserTokenFlowTest {
 					endpointsProvider, clientCredentials)
 							.token(invalidMockJwt)
 							.execute();
-		}).isInstanceOf(IllegalArgumentException.class)
+		}).isInstanceOf(IllegalStateException.class)
 				.hasMessageContaining("JWT token does not include scope 'uaa.user'");
 	}
 
diff --git a/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowsTest.java b/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowsTest.java
index 6ae122df..f42b6ff1 100644
--- a/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowsTest.java
+++ b/token-client/src/test/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowsTest.java
@@ -3,43 +3,41 @@ package com.sap.cloud.security.xsuaa.tokenflows;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.Assert.assertNotNull;
 
+import com.sap.cloud.security.xsuaa.client.*;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.springframework.web.client.RestTemplate;
 
-import com.sap.cloud.security.xsuaa.client.ClientCredentials;
-import com.sap.cloud.security.xsuaa.client.OAuth2ServiceEndpointsProvider;
-import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
-
 @RunWith(MockitoJUnitRunner.class)
 public class XsuaaTokenFlowsTest {
 
 	private XsuaaTokenFlows cut;
 	private ClientCredentials clientCredentials;
 	private OAuth2ServiceEndpointsProvider endpointsProvider;
+	private OAuth2TokenService oAuth2TokenService;
 
 	@Before
 	public void setup() {
 		this.clientCredentials = new ClientCredentials("clientId", "clientSecret");
 		this.endpointsProvider = new XsuaaDefaultEndpoints("http://base/");
-		cut = new XsuaaTokenFlows(new RestTemplate(),
-				this.endpointsProvider, clientCredentials);
+		this.oAuth2TokenService = new XsuaaOAuth2TokenService(new RestTemplate());
+		cut = new XsuaaTokenFlows(oAuth2TokenService, this.endpointsProvider, clientCredentials);
 	}
 
 	@Test
 	public void constructor_throwsOnNullValues() {
 		assertThatThrownBy(() -> {
 			new XsuaaTokenFlows(null, endpointsProvider, clientCredentials);
-		}).isInstanceOf(IllegalArgumentException.class).hasMessageStartingWith("RestOperations");
+		}).isInstanceOf(IllegalArgumentException.class).hasMessageStartingWith("OAuth2TokenService");
 
 		assertThatThrownBy(() -> {
-			new XsuaaTokenFlows(new RestTemplate(), null, clientCredentials);
+			new XsuaaTokenFlows(oAuth2TokenService, null, clientCredentials);
 		}).isInstanceOf(IllegalArgumentException.class).hasMessageStartingWith("OAuth2ServiceEndpointsProvider");
 
 		assertThatThrownBy(() -> {
-			new XsuaaTokenFlows(new RestTemplate(), endpointsProvider, null);
+			new XsuaaTokenFlows(oAuth2TokenService, endpointsProvider, null);
 		}).isInstanceOf(IllegalArgumentException.class).hasMessageStartingWith("ClientCredentials");
 
 	}