From e85b16d2533b0186a461c2d2dd15844f8ac5f72a Mon Sep 17 00:00:00 2001 From: Vaibhav Khamgaonkar <163758748+opensourcevk@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:57:53 +0000 Subject: [PATCH 1/4] feat: minor fix --- .../mastercard/developer/oauth2/http/UserAgent.java | 12 +++++++++--- .../oauth2/internal/json/GsonJsonProvider.java | 12 +++++++++--- .../oauth2/internal/json/JacksonJsonProvider.java | 6 ++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/library/src/main/java/com/mastercard/developer/oauth2/http/UserAgent.java b/library/src/main/java/com/mastercard/developer/oauth2/http/UserAgent.java index 885bcef..6deba10 100644 --- a/library/src/main/java/com/mastercard/developer/oauth2/http/UserAgent.java +++ b/library/src/main/java/com/mastercard/developer/oauth2/http/UserAgent.java @@ -12,22 +12,28 @@ public final class UserAgent { private static final String PRODUCT = "Mastercard-OAuth2-Client"; private static final String UNKNOWN_VERSION = "0.0.0-unknown"; private static final String VERSION = readVersionFile(); + // Cache the user-agent string to avoid rebuilding it on every call + private static final String CACHED_USER_AGENT = buildUserAgent(); private UserAgent() {} /** - * Builds a stable user-agent string: + * Returns a stable, pre-built user-agent string: * Product/Version (Runtime; OS [OS Version]) * Example: * Mastercard-OAuth2-Client/1.0.0 (Java/17.0.2; Linux 5.15) */ public static String get() { + return CACHED_USER_AGENT; + } + + private static String buildUserAgent() { String javaVer = System.getProperty("java.version", "unknown"); String osName = System.getProperty("os.name", "unknown"); String osVer = System.getProperty("os.version", "").trim(); - var runtime = "Java/" + javaVer; + String runtime = "Java/" + javaVer; String osPart = osName + (osVer.isEmpty() ? "" : " " + osVer); - return String.format("%s/%s (%s; %s)", PRODUCT, VERSION, runtime, osPart); + return PRODUCT + "/" + VERSION + " (" + runtime + "; " + osPart + ")"; } private static String readVersionFile() { diff --git a/library/src/main/java/com/mastercard/developer/oauth2/internal/json/GsonJsonProvider.java b/library/src/main/java/com/mastercard/developer/oauth2/internal/json/GsonJsonProvider.java index 73f3475..b383679 100644 --- a/library/src/main/java/com/mastercard/developer/oauth2/internal/json/GsonJsonProvider.java +++ b/library/src/main/java/com/mastercard/developer/oauth2/internal/json/GsonJsonProvider.java @@ -1,6 +1,7 @@ package com.mastercard.developer.oauth2.internal.json; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.mastercard.developer.oauth2.internal.json.exception.OAuth2ClientJsonException; import java.lang.reflect.Type; @@ -9,13 +10,18 @@ public class GsonJsonProvider implements JsonProvider { - private static final Gson gson = new Gson(); + // Use a configured Gson instance and cache the Map type to avoid allocating a new TypeToken on each parse. + private static final Gson gson = new GsonBuilder() + .disableHtmlEscaping() + .serializeNulls() + .create(); + + private static final Type MAP_TYPE = new TypeToken>() {}.getType(); @Override public Map parse(String json) throws OAuth2ClientJsonException { try { - Type type = new TypeToken>() {}.getType(); - return gson.fromJson(json, type); + return gson.fromJson(json, MAP_TYPE); } catch (Exception e) { throw new OAuth2ClientJsonException("Failed to read JSON", e); } diff --git a/library/src/main/java/com/mastercard/developer/oauth2/internal/json/JacksonJsonProvider.java b/library/src/main/java/com/mastercard/developer/oauth2/internal/json/JacksonJsonProvider.java index 0c1e161..0dc7443 100644 --- a/library/src/main/java/com/mastercard/developer/oauth2/internal/json/JacksonJsonProvider.java +++ b/library/src/main/java/com/mastercard/developer/oauth2/internal/json/JacksonJsonProvider.java @@ -10,11 +10,13 @@ public class JacksonJsonProvider implements JsonProvider { private static final ObjectMapper mapper = new ObjectMapper(); + // Cache the TypeReference to avoid creating a new anonymous subclass on each parse call. + private static final TypeReference> MAP_TYPE_REFERENCE = new TypeReference>() {}; + @Override public Map parse(String json) throws OAuth2ClientJsonException { try { - var typeReference = new TypeReference>() {}; - return mapper.readValue(json, typeReference); + return mapper.readValue(json, MAP_TYPE_REFERENCE); } catch (Exception e) { throw new OAuth2ClientJsonException("Failed to read JSON", e); } From f5b2d0e7134e38f5f7b5a6fb9d30247d01eec681 Mon Sep 17 00:00:00 2001 From: Jean-Alexis Aufauvre <3964455+jaaufauvre@users.noreply.github.com> Date: Fri, 16 Jan 2026 08:18:21 +0000 Subject: [PATCH 2/4] Removed line breaks --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d26c876..e1db088 100644 --- a/README.md +++ b/README.md @@ -364,4 +364,3 @@ cd library && mvn spotless:apply - The File Watchers plugin can format `.java` files on save - See watcher configuration in [`watcherTasks.xml`](./.idea/watcherTasks.xml) - From 35ee765abbfa2e57960c1b557d6fe02931d9f970 Mon Sep 17 00:00:00 2001 From: Jean-Alexis Aufauvre Date: Fri, 16 Jan 2026 09:47:41 +0000 Subject: [PATCH 3/4] Skipped real service tests when required environment variables are not set --- .../oauth2/test/fixtures/BaseClientTest.java | 60 ++++++------------- .../oauth2/test/fixtures/TestConfig.java | 23 ++++--- 2 files changed, 33 insertions(+), 50 deletions(-) diff --git a/library/src/test/java/com/mastercard/developer/oauth2/test/fixtures/BaseClientTest.java b/library/src/test/java/com/mastercard/developer/oauth2/test/fixtures/BaseClientTest.java index 78fb582..b85e653 100644 --- a/library/src/test/java/com/mastercard/developer/oauth2/test/fixtures/BaseClientTest.java +++ b/library/src/test/java/com/mastercard/developer/oauth2/test/fixtures/BaseClientTest.java @@ -11,7 +11,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Named; import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.function.ThrowingSupplier; import org.junit.jupiter.params.provider.Arguments; +import org.opentest4j.TestAbortedException; public abstract class BaseClientTest extends BaseTest { @@ -68,63 +70,27 @@ protected static Stream serverAndKeyProvider() { } protected static TestConfig getMastercardConfig() { - try { - return TestConfig.getMastercardApiConfig(); - } catch (IllegalStateException e) { - throw e; - } catch (Exception e) { - throw new IllegalStateException(e); - } + return runOrWrap(TestConfig::getMastercardApiConfig); } private static TestConfig getMastercardConfigWithEcKey() { - try { - return TestConfig.getMastercardApiConfig(StaticKeys.EC_KEY_PAIR); - } catch (IllegalStateException e) { - throw e; - } catch (Exception e) { - throw new IllegalStateException(e); - } + return runOrWrap(() -> TestConfig.getMastercardApiConfig(StaticKeys.EC_KEY_PAIR)); } private static TestConfig getMastercardConfigWithRsaKey() { - try { - return TestConfig.getMastercardApiConfig(StaticKeys.RSA_KEY_PAIR); - } catch (IllegalStateException e) { - throw e; - } catch (Exception e) { - throw new IllegalStateException(e); - } + return runOrWrap(() -> TestConfig.getMastercardApiConfig(StaticKeys.RSA_KEY_PAIR)); } protected static TestConfig getFakeConfig() { - try { - return TestConfig.getFakeApiConfig(authorizationServer, resourceServer); - } catch (IllegalStateException e) { - throw e; - } catch (Exception e) { - throw new IllegalStateException(e); - } + return runOrWrap(() -> TestConfig.getFakeApiConfig(authorizationServer, resourceServer)); } private static TestConfig getFakeConfigWithEcKey() { - try { - return TestConfig.getFakeApiConfig(authorizationServer, resourceServer, StaticKeys.EC_KEY_PAIR); - } catch (IllegalStateException e) { - throw e; - } catch (Exception e) { - throw new IllegalStateException(e); - } + return runOrWrap(() -> TestConfig.getFakeApiConfig(authorizationServer, resourceServer, StaticKeys.EC_KEY_PAIR)); } private static TestConfig getFakeConfigWithRsaKey() { - try { - return TestConfig.getFakeApiConfig(authorizationServer, resourceServer, StaticKeys.RSA_KEY_PAIR); - } catch (IllegalStateException e) { - throw e; - } catch (Exception e) { - throw new IllegalStateException(e); - } + return runOrWrap(() -> TestConfig.getFakeApiConfig(authorizationServer, resourceServer, StaticKeys.RSA_KEY_PAIR)); } private static Arguments createConfigArgument(String name, Supplier configSupplier) { @@ -135,4 +101,14 @@ protected static String readResourceId(String resource) throws OAuth2ClientJsonE Map jsonMap = JsonProvider.getInstance().parse(resource); return (String) jsonMap.get("id"); } + + private static T runOrWrap(ThrowingSupplier action) { + try { + return action.get(); + } catch (TestAbortedException | IllegalStateException e) { + throw e; + } catch (Throwable e) { + throw new IllegalStateException(e); + } + } } diff --git a/library/src/test/java/com/mastercard/developer/oauth2/test/fixtures/TestConfig.java b/library/src/test/java/com/mastercard/developer/oauth2/test/fixtures/TestConfig.java index 6fce0eb..7a7c77f 100644 --- a/library/src/test/java/com/mastercard/developer/oauth2/test/fixtures/TestConfig.java +++ b/library/src/test/java/com/mastercard/developer/oauth2/test/fixtures/TestConfig.java @@ -1,5 +1,7 @@ package com.mastercard.developer.oauth2.test.fixtures; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + import com.mastercard.developer.oauth2.config.OAuth2Config; import com.mastercard.developer.oauth2.config.SecurityProfile; import com.mastercard.developer.oauth2.core.dpop.StaticDPoPKeyProvider; @@ -51,14 +53,19 @@ public static TestConfig getMastercardApiConfig(KeyPair dpopKeyPair) throws Exce String readScopes = getEnv("READ_SCOPES"); String writeScopes = getEnv("WRITE_SCOPES"); - validateEnvVariable("PRIVATE_KEY", privateKeyContent); - validateEnvVariable("CLIENT_ID", clientId); - validateEnvVariable("KID", kid); - validateEnvVariable("TOKEN_ENDPOINT", tokenEndpoint); - validateEnvVariable("ISSUER", issuer); - validateEnvVariable("API_BASE_URL", apiBaseUrlEnv); - validateEnvVariable("READ_SCOPES", readScopes); - validateEnvVariable("WRITE_SCOPES", readScopes); + try { + validateEnvVariable("PRIVATE_KEY", privateKeyContent); + validateEnvVariable("CLIENT_ID", clientId); + validateEnvVariable("KID", kid); + validateEnvVariable("TOKEN_ENDPOINT", tokenEndpoint); + validateEnvVariable("ISSUER", issuer); + validateEnvVariable("API_BASE_URL", apiBaseUrlEnv); + validateEnvVariable("READ_SCOPES", readScopes); + validateEnvVariable("WRITE_SCOPES", readScopes); + } catch (Exception e) { + // Disable the calling test when environment variables are missing + assumeTrue(false, "Test disabled: %s".formatted(e.getMessage())); + } OAuth2Config oauth2Config = OAuth2Config.builder() .securityProfile(SecurityProfile.FAPI2SP_PRIVATE_KEY_DPOP) From 922a68dca86f4ade570b622a045ec1ab1b404eaa Mon Sep 17 00:00:00 2001 From: Jean-Alexis Aufauvre Date: Fri, 16 Jan 2026 10:01:26 +0000 Subject: [PATCH 4/4] Clean-up --- .../mastercard/developer/oauth2/http/UserAgent.java | 10 ++-------- .../oauth2/internal/json/GsonJsonProvider.java | 8 +------- .../oauth2/internal/json/JacksonJsonProvider.java | 4 +--- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/library/src/main/java/com/mastercard/developer/oauth2/http/UserAgent.java b/library/src/main/java/com/mastercard/developer/oauth2/http/UserAgent.java index 6deba10..48da140 100644 --- a/library/src/main/java/com/mastercard/developer/oauth2/http/UserAgent.java +++ b/library/src/main/java/com/mastercard/developer/oauth2/http/UserAgent.java @@ -12,28 +12,22 @@ public final class UserAgent { private static final String PRODUCT = "Mastercard-OAuth2-Client"; private static final String UNKNOWN_VERSION = "0.0.0-unknown"; private static final String VERSION = readVersionFile(); - // Cache the user-agent string to avoid rebuilding it on every call - private static final String CACHED_USER_AGENT = buildUserAgent(); private UserAgent() {} /** - * Returns a stable, pre-built user-agent string: + * Builds a stable user-agent string: * Product/Version (Runtime; OS [OS Version]) * Example: * Mastercard-OAuth2-Client/1.0.0 (Java/17.0.2; Linux 5.15) */ public static String get() { - return CACHED_USER_AGENT; - } - - private static String buildUserAgent() { String javaVer = System.getProperty("java.version", "unknown"); String osName = System.getProperty("os.name", "unknown"); String osVer = System.getProperty("os.version", "").trim(); String runtime = "Java/" + javaVer; String osPart = osName + (osVer.isEmpty() ? "" : " " + osVer); - return PRODUCT + "/" + VERSION + " (" + runtime + "; " + osPart + ")"; + return String.format("%s/%s (%s; %s)", PRODUCT, VERSION, runtime, osPart); } private static String readVersionFile() { diff --git a/library/src/main/java/com/mastercard/developer/oauth2/internal/json/GsonJsonProvider.java b/library/src/main/java/com/mastercard/developer/oauth2/internal/json/GsonJsonProvider.java index b383679..7400757 100644 --- a/library/src/main/java/com/mastercard/developer/oauth2/internal/json/GsonJsonProvider.java +++ b/library/src/main/java/com/mastercard/developer/oauth2/internal/json/GsonJsonProvider.java @@ -1,7 +1,6 @@ package com.mastercard.developer.oauth2.internal.json; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.mastercard.developer.oauth2.internal.json.exception.OAuth2ClientJsonException; import java.lang.reflect.Type; @@ -10,12 +9,7 @@ public class GsonJsonProvider implements JsonProvider { - // Use a configured Gson instance and cache the Map type to avoid allocating a new TypeToken on each parse. - private static final Gson gson = new GsonBuilder() - .disableHtmlEscaping() - .serializeNulls() - .create(); - + private static final Gson gson = new Gson(); private static final Type MAP_TYPE = new TypeToken>() {}.getType(); @Override diff --git a/library/src/main/java/com/mastercard/developer/oauth2/internal/json/JacksonJsonProvider.java b/library/src/main/java/com/mastercard/developer/oauth2/internal/json/JacksonJsonProvider.java index 0dc7443..26dc58d 100644 --- a/library/src/main/java/com/mastercard/developer/oauth2/internal/json/JacksonJsonProvider.java +++ b/library/src/main/java/com/mastercard/developer/oauth2/internal/json/JacksonJsonProvider.java @@ -9,9 +9,7 @@ public class JacksonJsonProvider implements JsonProvider { private static final ObjectMapper mapper = new ObjectMapper(); - - // Cache the TypeReference to avoid creating a new anonymous subclass on each parse call. - private static final TypeReference> MAP_TYPE_REFERENCE = new TypeReference>() {}; + private static final TypeReference> MAP_TYPE_REFERENCE = new TypeReference<>() {}; @Override public Map parse(String json) throws OAuth2ClientJsonException {