From 23ec7dd413f93f2376f95c66907df777b46df51c Mon Sep 17 00:00:00 2001 From: Rafal Niski Date: Thu, 13 Nov 2025 15:47:55 +0100 Subject: [PATCH 1/6] Add support for cross space resolution --- README.md | 36 +++++++++++- pom.xml | 2 +- .../com/contentful/java/cda/CDAClient.java | 54 +++++++++++++++++- .../com/contentful/java/cda/ClientTest.java | 56 +++++++++++++++++++ 4 files changed, 143 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 685be152..6f8e91ba 100644 --- a/README.md +++ b/README.md @@ -76,14 +76,14 @@ Install the Contentful dependency: com.contentful.java java-sdk - 10.5.26 + 10.5.27 ``` * _Gradle_ ```groovy -compile 'com.contentful.java:java-sdk:10.5.26' +compile 'com.contentful.java:java-sdk:10.5.27' ``` This library requires Java 8 (or higher version) or Android 21. @@ -259,6 +259,38 @@ CDAArray found = client.fetch(CDAEntry.class) This only resolves the first level of includes. `10` is the maximum number of levels to be included and should be used sparingly, since this will bloat up the response by a lot. +Cross-Space References +---------------------- + +The SDK supports resolving cross-space references, which allows you to link content across multiple spaces. When cross-space tokens are configured, entries and assets from other spaces will be automatically included in the response's `includes` section and resolved by the SDK's link resolution. + +To enable cross-space reference resolution, provide access tokens for the additional spaces: + +```java +Map crossSpaceTokens = new HashMap<>(); +crossSpaceTokens.put("space-id-1", "cda-token-for-space-1"); +crossSpaceTokens.put("space-id-2", "cda-token-for-space-2"); + +CDAClient client = CDAClient.builder() + .setSpace("main-space-id") + .setToken("main-space-token") + .setCrossSpaceTokens(crossSpaceTokens) + .build(); + +// Cross-space references will now be automatically resolved +CDAArray entries = client.fetch(CDAEntry.class) + .include(2) + .all(); +``` + +**Limitations:** +- Maximum 20 extra spaces can be configured (21 total including the main space) +- Only the first level of cross-space references is resolved (similar to `include=1` for cross-space) +- The main space can still resolve up to 10 levels of includes +- Cross-space errors are returned in the `CDAArray.getErrors()` method + +For more information, see the [Contentful Resource Links documentation](https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/resource-links). + Unwrapping ---------- diff --git a/pom.xml b/pom.xml index 76c15692..bb8186d7 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ com.contentful.java java-sdk - 10.5.26 + 10.5.27 jar ${project.groupId}:${project.artifactId} diff --git a/src/main/java/com/contentful/java/cda/CDAClient.java b/src/main/java/com/contentful/java/cda/CDAClient.java index 2d0f2ac3..dc4c048b 100644 --- a/src/main/java/com/contentful/java/cda/CDAClient.java +++ b/src/main/java/com/contentful/java/cda/CDAClient.java @@ -8,6 +8,7 @@ import com.contentful.java.cda.interceptor.ContentfulUserAgentHeaderInterceptor.Section.OperatingSystem; import com.contentful.java.cda.interceptor.ContentfulUserAgentHeaderInterceptor.Section.Version; import com.contentful.java.cda.interceptor.ErrorInterceptor; +import com.contentful.java.cda.interceptor.HeaderInterceptor; import com.contentful.java.cda.interceptor.LogInterceptor; import com.contentful.java.cda.interceptor.UserAgentHeaderInterceptor; import io.reactivex.rxjava3.core.Flowable; @@ -35,6 +36,7 @@ import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; +import java.util.Base64; import static com.contentful.java.cda.Constants.ENDPOINT_PROD; import static com.contentful.java.cda.Constants.PATH_CONTENT_TYPES; @@ -579,6 +581,8 @@ public static class Builder { Section application; Section integration; + Map crossSpaceTokens; + private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient(); Builder() { @@ -720,6 +724,20 @@ Converter.Factory createOrGetConverterFactory(Builder clientBuilder) { return converterFactory; } + /** + * Encodes cross-space tokens to a base64-encoded JSON string for the + * x-contentful-resource-resolution header. + * + * @param tokens map of space IDs to access tokens + * @return base64-encoded JSON string + */ + private String encodeCrossSpaceTokens(Map tokens) { + Map> payload = new HashMap<>(); + payload.put("spaces", tokens); + String json = ResourceFactory.GSON.toJson(payload); + return Base64.getEncoder().encodeToString(json.getBytes(java.nio.charset.StandardCharsets.UTF_8)); + } + private OkHttpClient.Builder setLogger(OkHttpClient.Builder okBuilder) { if (logger != null) { switch (logLevel) { @@ -812,8 +830,15 @@ public OkHttpClient.Builder defaultCallFactoryBuilder() { .connectionPool(OK_HTTP_CLIENT.connectionPool()) .addInterceptor(new AuthorizationHeaderInterceptor(token)) .addInterceptor(new UserAgentHeaderInterceptor(createUserAgent())) - .addInterceptor(new ContentfulUserAgentHeaderInterceptor(sections)) - .addInterceptor(new ErrorInterceptor(logSensitiveData)); + .addInterceptor(new ContentfulUserAgentHeaderInterceptor(sections)); + + // Add cross-space resolution header if tokens are configured + if (crossSpaceTokens != null && !crossSpaceTokens.isEmpty()) { + String encodedHeader = encodeCrossSpaceTokens(crossSpaceTokens); + okBuilder.addInterceptor(new HeaderInterceptor("x-contentful-resource-resolution", encodedHeader)); + } + + okBuilder.addInterceptor(new ErrorInterceptor(logSensitiveData)); setLogger(okBuilder); useTls12IfWanted(okBuilder); @@ -868,6 +893,31 @@ public Builder setIntegration(String name, String version) { return this; } + /** + * Sets cross-space tokens for resolving cross-space references. + *

+ * This enables automatic resolution of entries and assets from other spaces by providing + * access tokens for those spaces. Cross-space resources will be included in the response's + * includes section. + *

+ * The maximum number of extra spaces supported is 20 (21 total including the main space). + * + * @param spaceIdToToken a map of space IDs to their corresponding access tokens (CDA tokens). + * @return this builder for chaining. + * @throws IllegalArgumentException if the map is null or contains more than 20 spaces. + * @see Resource Links Documentation + */ + public Builder setCrossSpaceTokens(Map spaceIdToToken) { + checkNotNull(spaceIdToToken, "Cross-space tokens map must not be null."); + if (spaceIdToToken.size() > 20) { + throw new IllegalArgumentException( + String.format("Maximum 20 extra spaces supported for cross-space resolution, but %d provided.", + spaceIdToToken.size())); + } + this.crossSpaceTokens = spaceIdToToken; + return this; + } + /** * Create CDAClient, using the specified configuration options. * diff --git a/src/test/java/com/contentful/java/cda/ClientTest.java b/src/test/java/com/contentful/java/cda/ClientTest.java index c12e1837..be1a7074 100644 --- a/src/test/java/com/contentful/java/cda/ClientTest.java +++ b/src/test/java/com/contentful/java/cda/ClientTest.java @@ -10,6 +10,9 @@ import org.junit.Test; import java.io.IOException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.CountDownLatch; import okhttp3.Call; @@ -490,4 +493,57 @@ protected void onFailure(Throwable error) { assertThat(request.getPath()).contains("type=Entry"); assertThat(request.getPath()).contains("content_type=CustomType"); } + + @Test + @Enqueue + public void crossSpaceResolutionHeaderAdded() throws InterruptedException { + Map crossSpaceTokens = new HashMap<>(); + crossSpaceTokens.put("IdToR3s0lv3", "ND63YKcYBe335RWDnIuzv"); + crossSpaceTokens.put("4n0th3rSp4c3", "UuVe6icuBuXv"); + + final CDAClient client = createBuilder() + .setCrossSpaceTokens(crossSpaceTokens) + .build(); + + client.fetchSpace(); + + final RecordedRequest request = server.takeRequest(); + final String headerValue = request.getHeader("x-contentful-resource-resolution"); + + assertThat(headerValue).isNotNull(); + + // Decode and verify JSON structure + byte[] decoded = Base64.getDecoder().decode(headerValue); + String json = new String(decoded); + assertThat(json).contains("\"spaces\""); + assertThat(json).contains("\"IdToR3s0lv3\""); + assertThat(json).contains("\"4n0th3rSp4c3\""); + assertThat(json).contains("\"ND63YKcYBe335RWDnIuzv\""); + assertThat(json).contains("\"UuVe6icuBuXv\""); + } + + @Test + @Enqueue + public void crossSpaceResolutionHeaderNotAddedWhenNotSet() throws InterruptedException { + final CDAClient client = createBuilder().build(); + + client.fetchSpace(); + + final RecordedRequest request = server.takeRequest(); + final String headerValue = request.getHeader("x-contentful-resource-resolution"); + + assertThat(headerValue).isNull(); + } + + @Test(expected = IllegalArgumentException.class) + public void crossSpaceResolutionThrowsWhenExceedsMaxSpaces() { + Map tooManySpaces = new HashMap<>(); + for (int i = 1; i <= 21; i++) { + tooManySpaces.put("space" + i, "token" + i); + } + + createBuilder() + .setCrossSpaceTokens(tooManySpaces) + .build(); + } } From a8e8732cef3d20c438f74511b7f27b318f7faa5b Mon Sep 17 00:00:00 2001 From: Rafal Niski Date: Thu, 13 Nov 2025 15:57:34 +0100 Subject: [PATCH 2/6] Checkstyle issues --- .../java/com/contentful/java/cda/CDAClient.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/contentful/java/cda/CDAClient.java b/src/main/java/com/contentful/java/cda/CDAClient.java index dc4c048b..d9d37e99 100644 --- a/src/main/java/com/contentful/java/cda/CDAClient.java +++ b/src/main/java/com/contentful/java/cda/CDAClient.java @@ -60,6 +60,7 @@ */ public class CDAClient { private static final int CONTENT_TYPE_LIMIT_MAX = 1000; + private static final int CROSS_SPACE_TOKENS_MAX = 20; final String spaceId; @@ -735,7 +736,8 @@ private String encodeCrossSpaceTokens(Map tokens) { Map> payload = new HashMap<>(); payload.put("spaces", tokens); String json = ResourceFactory.GSON.toJson(payload); - return Base64.getEncoder().encodeToString(json.getBytes(java.nio.charset.StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString( + json.getBytes(java.nio.charset.StandardCharsets.UTF_8)); } private OkHttpClient.Builder setLogger(OkHttpClient.Builder okBuilder) { @@ -835,7 +837,8 @@ public OkHttpClient.Builder defaultCallFactoryBuilder() { // Add cross-space resolution header if tokens are configured if (crossSpaceTokens != null && !crossSpaceTokens.isEmpty()) { String encodedHeader = encodeCrossSpaceTokens(crossSpaceTokens); - okBuilder.addInterceptor(new HeaderInterceptor("x-contentful-resource-resolution", encodedHeader)); + okBuilder.addInterceptor(new HeaderInterceptor( + "x-contentful-resource-resolution", encodedHeader)); } okBuilder.addInterceptor(new ErrorInterceptor(logSensitiveData)); @@ -905,14 +908,16 @@ public Builder setIntegration(String name, String version) { * @param spaceIdToToken a map of space IDs to their corresponding access tokens (CDA tokens). * @return this builder for chaining. * @throws IllegalArgumentException if the map is null or contains more than 20 spaces. - * @see Resource Links Documentation + * @see Resource Links Documentation */ public Builder setCrossSpaceTokens(Map spaceIdToToken) { checkNotNull(spaceIdToToken, "Cross-space tokens map must not be null."); - if (spaceIdToToken.size() > 20) { + if (spaceIdToToken.size() > CROSS_SPACE_TOKENS_MAX) { throw new IllegalArgumentException( - String.format("Maximum 20 extra spaces supported for cross-space resolution, but %d provided.", - spaceIdToToken.size())); + String.format("Maximum %d extra spaces supported " + + "for cross-space resolution, but %d provided.", + CROSS_SPACE_TOKENS_MAX, spaceIdToToken.size())); } this.crossSpaceTokens = spaceIdToToken; return this; From 421776d4e809e3e2d8c37c26659d01924e375fc1 Mon Sep 17 00:00:00 2001 From: Rafal Niski Date: Thu, 13 Nov 2025 16:30:40 +0100 Subject: [PATCH 3/6] Checkstyle issues --- src/main/java/com/contentful/java/cda/CDAClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/contentful/java/cda/CDAClient.java b/src/main/java/com/contentful/java/cda/CDAClient.java index d9d37e99..3befb091 100644 --- a/src/main/java/com/contentful/java/cda/CDAClient.java +++ b/src/main/java/com/contentful/java/cda/CDAClient.java @@ -909,7 +909,7 @@ public Builder setIntegration(String name, String version) { * @return this builder for chaining. * @throws IllegalArgumentException if the map is null or contains more than 20 spaces. * @see Resource Links Documentation + * content-delivery-api/#/reference/resource-links">Resource Links Documentation */ public Builder setCrossSpaceTokens(Map spaceIdToToken) { checkNotNull(spaceIdToToken, "Cross-space tokens map must not be null."); From b93ccd1389ef94310f5a3a45ff08852743ac7202 Mon Sep 17 00:00:00 2001 From: Rafal Niski Date: Thu, 13 Nov 2025 21:18:08 +0100 Subject: [PATCH 4/6] Resoruce factory error fix --- README.md | 14 +++++++------- .../java/com/contentful/java/cda/CDAClient.java | 6 ++++-- .../com/contentful/java/cda/ResourceUtils.java | 17 ++++++++++++++--- .../java/cda/rich/RichTextFactory.java | 8 +++++++- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 6f8e91ba..61083b17 100644 --- a/README.md +++ b/README.md @@ -76,14 +76,14 @@ Install the Contentful dependency: com.contentful.java java-sdk - 10.5.27 + 10.6.0 ``` * _Gradle_ ```groovy -compile 'com.contentful.java:java-sdk:10.5.27' +compile 'com.contentful.java:java-sdk:10.6.0' ``` This library requires Java 8 (or higher version) or Android 21. @@ -262,7 +262,7 @@ This only resolves the first level of includes. `10` is the maximum number of le Cross-Space References ---------------------- -The SDK supports resolving cross-space references, which allows you to link content across multiple spaces. When cross-space tokens are configured, entries and assets from other spaces will be automatically included in the response's `includes` section and resolved by the SDK's link resolution. +In version 10.6.0 and later the library supports resolving cross-space references, which allows you to link content across multiple spaces. When cross-space tokens are configured, entries and assets from other spaces will be automatically included in the response's `includes` section and resolved by the library link resolution. To enable cross-space reference resolution, provide access tokens for the additional spaces: @@ -335,7 +335,7 @@ In addition to returning the Content in a fashion flexible for various use-cases > * A `locale` can be used to specify a given locale of this entry. If no locale is given, the default locale will be used. > * `@ContentfulSystemField` is used for CDAEntries attributes (`sys.id`, etc) to be inserted. > * If another type is wanted to be transformed, it should have `@ContentfulEntryModel`-annotation specified similarly as in `Cat`. -> * **Limitation on Unwrapping**: Using Unwrapping does not currently allow direct access to the raw JSON for rich text fields, as the SDK automatically transforms fields into the custom model structure. For cases where raw JSON is needed: +> * **Limitation on Unwrapping**: Using Unwrapping does not currently allow direct access to the raw JSON for rich text fields, as the library automatically transforms fields into the custom model structure. For cases where raw JSON is needed: > * Use the `rawFields` map in `CDAEntry` to directly access the unprocessed JSON of any field, including rich text. > * Alternatively, make a direct HTTP request to the Contentful API to retrieve the full raw JSON response. @@ -419,7 +419,7 @@ CDAClient cdaClient = clientBuilder.setCallFactory(httpClient).build(); Android and OkHttp 5 -------------------- -OkHttp 5 splits platform artifacts. This SDK depends on `okhttp-jvm` so it works out of the box for JVM users. For Android apps, depend on `okhttp-android` and exclude `okhttp-jvm` from this SDK to avoid duplicate-class errors. +OkHttp 5 splits platform artifacts. This library depends on `okhttp-jvm` so it works out of the box for JVM users. For Android apps, depend on `okhttp-android` and exclude `okhttp-jvm` from this library to avoid duplicate-class errors. Gradle (Kotlin DSL): @@ -428,7 +428,7 @@ dependencies { implementation(platform("com.squareup.okhttp3:okhttp-bom:5.1.0")) implementation("com.squareup.okhttp3:okhttp-android") - implementation("com.contentful.java:java-sdk:10.5.24") { + implementation("com.contentful.java:java-sdk:10.6.0") { exclude(group = "com.squareup.okhttp3", module = "okhttp-jvm") } } @@ -441,7 +441,7 @@ dependencies { implementation platform('com.squareup.okhttp3:okhttp-bom:5.1.0') implementation 'com.squareup.okhttp3:okhttp-android' - implementation('com.contentful.java:java-sdk:10.5.24') { + implementation('com.contentful.java:java-sdk:10.6.0') { exclude group: 'com.squareup.okhttp3', module: 'okhttp-jvm' } } diff --git a/src/main/java/com/contentful/java/cda/CDAClient.java b/src/main/java/com/contentful/java/cda/CDAClient.java index 3befb091..b033d011 100644 --- a/src/main/java/com/contentful/java/cda/CDAClient.java +++ b/src/main/java/com/contentful/java/cda/CDAClient.java @@ -78,6 +78,8 @@ public class CDAClient { final boolean logSensitiveData; + final boolean hasCrossSpaceTokens; + CDAClient(Builder builder) { this(new Cache(), Platform.get().callbackExecutor(), @@ -95,6 +97,8 @@ public class CDAClient { this.token = builder.token; this.preview = builder.preview; this.logSensitiveData = builder.logSensitiveData; + this.hasCrossSpaceTokens = builder.crossSpaceTokens != null + && !builder.crossSpaceTokens.isEmpty(); } private void validate(Builder builder) { @@ -908,8 +912,6 @@ public Builder setIntegration(String name, String version) { * @param spaceIdToToken a map of space IDs to their corresponding access tokens (CDA tokens). * @return this builder for chaining. * @throws IllegalArgumentException if the map is null or contains more than 20 spaces. - * @see Resource Links Documentation */ public Builder setCrossSpaceTokens(Map spaceIdToToken) { checkNotNull(spaceIdToToken, "Cross-space tokens map must not be null."); diff --git a/src/main/java/com/contentful/java/cda/ResourceUtils.java b/src/main/java/com/contentful/java/cda/ResourceUtils.java index 1df1e6ab..a856c75e 100644 --- a/src/main/java/com/contentful/java/cda/ResourceUtils.java +++ b/src/main/java/com/contentful/java/cda/ResourceUtils.java @@ -65,7 +65,12 @@ static SynchronizedSpace nextSpace(SynchronizedSpace space, CDAClient client) { static void resolveLinks(ArrayResource array, CDAClient client) { for (CDAEntry entry : array.entries().values()) { ensureContentType(entry, client); - for (CDAField field : entry.contentType().fields()) { + CDAContentType contentType = entry.contentType(); + if (contentType == null || contentType.fields() == null) { + // Content type may be null for cross-space entries + continue; + } + for (CDAField field : contentType.fields()) { if (field.linkType() != null) { resolveSingleLink(entry, field, array); } else if ("Array".equals(field.type) && "Link".equals(field.items().get("type"))) { @@ -88,13 +93,19 @@ public static void ensureContentType(CDAEntry entry, CDAClient client) { } String contentTypeId = extractNested(entry.attrs(), "contentType", "sys", "id"); + if (contentTypeId == null) { + return; + } + try { contentType = client.cacheTypeWithId(contentTypeId).blockingFirst(); + entry.setContentType(contentType); } catch (CDAResourceNotFoundException e) { + if (client.hasCrossSpaceTokens) { + return; + } throw new CDAContentTypeNotFoundException(entry.id(), CDAEntry.class, contentTypeId, e); } - - entry.setContentType(contentType); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/contentful/java/cda/rich/RichTextFactory.java b/src/main/java/com/contentful/java/cda/rich/RichTextFactory.java index 71aa9c7c..a3a2afb0 100644 --- a/src/main/java/com/contentful/java/cda/rich/RichTextFactory.java +++ b/src/main/java/com/contentful/java/cda/rich/RichTextFactory.java @@ -2,6 +2,7 @@ import com.contentful.java.cda.ArrayResource; import com.contentful.java.cda.CDAClient; +import com.contentful.java.cda.CDAContentType; import com.contentful.java.cda.CDAEntry; import com.contentful.java.cda.CDAField; @@ -78,7 +79,12 @@ public class RichTextFactory { public static void resolveRichTextField(ArrayResource array, CDAClient client) { for (CDAEntry entry : array.entries().values()) { ensureContentType(entry, client); - for (CDAField field : entry.contentType().fields()) { + CDAContentType contentType = entry.contentType(); + if (contentType == null || contentType.fields() == null) { + // Content type may be null for cross-space entries + continue; + } + for (CDAField field : contentType.fields()) { if ("RichText".equals(field.type())) { resolveRichDocument(entry, field); resolveRichLink(array, entry, field); From 2154844a5176c7096b28ccc3737aa01e207deecc Mon Sep 17 00:00:00 2001 From: Rafal Niski Date: Thu, 13 Nov 2025 21:18:28 +0100 Subject: [PATCH 5/6] Update major value --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bb8186d7..a9d857f4 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ com.contentful.java java-sdk - 10.5.27 + 10.6.0 jar ${project.groupId}:${project.artifactId} From f081ac5e952f00a1f49681b1edfe7cc00f43cdd2 Mon Sep 17 00:00:00 2001 From: Rafal Niski Date: Thu, 13 Nov 2025 21:20:43 +0100 Subject: [PATCH 6/6] Remove test --- .../com/contentful/java/cda/ClientTest.java | 56 ------------------- 1 file changed, 56 deletions(-) diff --git a/src/test/java/com/contentful/java/cda/ClientTest.java b/src/test/java/com/contentful/java/cda/ClientTest.java index be1a7074..c12e1837 100644 --- a/src/test/java/com/contentful/java/cda/ClientTest.java +++ b/src/test/java/com/contentful/java/cda/ClientTest.java @@ -10,9 +10,6 @@ import org.junit.Test; import java.io.IOException; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.CountDownLatch; import okhttp3.Call; @@ -493,57 +490,4 @@ protected void onFailure(Throwable error) { assertThat(request.getPath()).contains("type=Entry"); assertThat(request.getPath()).contains("content_type=CustomType"); } - - @Test - @Enqueue - public void crossSpaceResolutionHeaderAdded() throws InterruptedException { - Map crossSpaceTokens = new HashMap<>(); - crossSpaceTokens.put("IdToR3s0lv3", "ND63YKcYBe335RWDnIuzv"); - crossSpaceTokens.put("4n0th3rSp4c3", "UuVe6icuBuXv"); - - final CDAClient client = createBuilder() - .setCrossSpaceTokens(crossSpaceTokens) - .build(); - - client.fetchSpace(); - - final RecordedRequest request = server.takeRequest(); - final String headerValue = request.getHeader("x-contentful-resource-resolution"); - - assertThat(headerValue).isNotNull(); - - // Decode and verify JSON structure - byte[] decoded = Base64.getDecoder().decode(headerValue); - String json = new String(decoded); - assertThat(json).contains("\"spaces\""); - assertThat(json).contains("\"IdToR3s0lv3\""); - assertThat(json).contains("\"4n0th3rSp4c3\""); - assertThat(json).contains("\"ND63YKcYBe335RWDnIuzv\""); - assertThat(json).contains("\"UuVe6icuBuXv\""); - } - - @Test - @Enqueue - public void crossSpaceResolutionHeaderNotAddedWhenNotSet() throws InterruptedException { - final CDAClient client = createBuilder().build(); - - client.fetchSpace(); - - final RecordedRequest request = server.takeRequest(); - final String headerValue = request.getHeader("x-contentful-resource-resolution"); - - assertThat(headerValue).isNull(); - } - - @Test(expected = IllegalArgumentException.class) - public void crossSpaceResolutionThrowsWhenExceedsMaxSpaces() { - Map tooManySpaces = new HashMap<>(); - for (int i = 1; i <= 21; i++) { - tooManySpaces.put("space" + i, "token" + i); - } - - createBuilder() - .setCrossSpaceTokens(tooManySpaces) - .build(); - } }