From 6f587b4d7e90d8d36410177064588e7aba14a082 Mon Sep 17 00:00:00 2001 From: Tom Reznik Date: Thu, 1 Jan 2015 14:18:25 +0200 Subject: [PATCH] Nullify unresolved links (optional) --- .../com/contentful/java/cda/ArrayParser.java | 55 ++++++--- .../com/contentful/java/cda/CDAClient.java | 15 ++- .../contentful/java/cda/ClientContext.java | 4 +- .../com/contentful/java/cda/BaseTest.kt | 2 +- .../com/contentful/java/cda/EntryTests.kt | 33 +++++ .../entry_fetch_all_unresolved_link.json | 113 ++++++++++++++++++ 6 files changed, 203 insertions(+), 19 deletions(-) create mode 100644 src/test/resources/entry_fetch_all_unresolved_link.json diff --git a/src/main/java/com/contentful/java/cda/ArrayParser.java b/src/main/java/com/contentful/java/cda/ArrayParser.java index 595fd82e..4f870038 100644 --- a/src/main/java/com/contentful/java/cda/ArrayParser.java +++ b/src/main/java/com/contentful/java/cda/ArrayParser.java @@ -26,6 +26,7 @@ import com.contentful.java.cda.model.ResourceWithMap; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -98,7 +99,7 @@ public ArrayParser(T source, ClientContext context) { CDAResource item = entry.getValue(); if (item instanceof ResourceWithMap) { - resolveResourceLinks(item, assets, entries); + resolveResourceLinks((ResourceWithMap) item, assets, entries); } } @@ -128,47 +129,69 @@ private void setLocalizedFields(ResourceWithMap res) { } /** - * Resolves any links contained in a {@code CDAEntry} object. + * Resolves any links contained in a {@code ResourceWithMap} object. * - * @param resource entry to resolve + * @param res entry to resolve * @param assets map of assets by ids * @param entries map of entries by ids */ @SuppressWarnings("unchecked") - private void resolveResourceLinks(CDAResource resource, - HashMap assets, HashMap entries) { - ResourceWithMap res = (ResourceWithMap) resource; + private void resolveResourceLinks(ResourceWithMap res, HashMap assets, + HashMap entries) { HashMap localizedFields = res.getLocalizedFieldsMap(); for (Map fields : localizedFields.values()) { + HashSet removeFromFields = new HashSet(); + for (Object k : fields.keySet()) { Object value = fields.get(k); if (value instanceof Map) { - CDAResource match = getMatchForField((Map) value, assets, entries); - - if (match != null) { - fields.put(k, match); + Map sys = (Map) ((Map) value).get("sys"); + if (sys != null && containsLink(sys)) { + CDAResource match = getMatchForField((Map) value, assets, entries); + if (match != null) { + fields.put(k, match); + } else if (context.nullifyUnresolved) { + removeFromFields.add(k); + } } } else if (value instanceof List) { List list = (List) value; + List modifiedList = new ArrayList(); - for (int i = 0; i < list.size(); i++) { - Object item = list.get(i); + for (Object item : list) { + modifiedList.add(item); + int pos = modifiedList.size() - 1; if (item instanceof Map) { - CDAResource match = getMatchForField((Map) item, assets, entries); - - if (match != null) { - list.set(i, match); + Map sys = (Map) ((Map) item).get("sys"); + if (sys != null && containsLink(sys)) { + CDAResource match = getMatchForField((Map) item, assets, entries); + if (match != null) { + modifiedList.set(pos, match); + } else if (context.nullifyUnresolved) { + modifiedList.remove(pos); + } } } } + + fields.put(k, modifiedList); } } + + if (removeFromFields.size() > 0) { + fields.keySet().removeAll(removeFromFields); + } } } + private boolean containsLink(Map map) { + String type = (String) map.get("type"); + return CDAResourceType.Link.equals(CDAResourceType.valueOf(type)); + } + /** * Resolves field link. * diff --git a/src/main/java/com/contentful/java/cda/CDAClient.java b/src/main/java/com/contentful/java/cda/CDAClient.java index 97892a36..05968f0d 100644 --- a/src/main/java/com/contentful/java/cda/CDAClient.java +++ b/src/main/java/com/contentful/java/cda/CDAClient.java @@ -85,7 +85,7 @@ private CDAClient(Builder builder) { // Modules ClientContext context = new ClientContext(service, callbackExecutor, spaceKey, - gson, spaceWrapper, classMap); + gson, spaceWrapper, classMap, builder.nullifyUnresolved); this.moduleAssets = new ModuleAssets(context); this.moduleContentTypes = new ModuleContentTypes(context); @@ -266,10 +266,12 @@ public static class Builder { Executor callbackExecutor; Map> classMap; boolean secure; + boolean nullifyUnresolved; public Builder() { // Defaults this.secure = true; + this.nullifyUnresolved = false; } /** @@ -427,6 +429,17 @@ public Builder preview() { return setEndpoint(Constants.ENDPOINT_PREVIEW); } + /** + * By default, unresolved links will point to a {@code Map} instance containing all the links + * details. This changes the default behaviour to remove any unresolved links. + * + * @return this {@code Builder} instance + */ + public Builder nullifyUnresolvedLinks() { + this.nullifyUnresolved = true; + return this; + } + /** * Builds and returns a {@link CDAClient} * diff --git a/src/main/java/com/contentful/java/cda/ClientContext.java b/src/main/java/com/contentful/java/cda/ClientContext.java index 59f030a2..268dc469 100644 --- a/src/main/java/com/contentful/java/cda/ClientContext.java +++ b/src/main/java/com/contentful/java/cda/ClientContext.java @@ -30,14 +30,16 @@ final class ClientContext { final Gson gson; final SpaceWrapper spaceWrapper; final Map> customTypesMap; + final boolean nullifyUnresolved; public ClientContext(CDAService service, Executor callbackExecutor, String spaceId, Gson gson, - SpaceWrapper spaceWrapper, Map> customTypesMap) { + SpaceWrapper spaceWrapper, Map> customTypesMap, boolean nullifyUnresolved) { this.service = service; this.callbackExecutor = callbackExecutor; this.spaceId = spaceId; this.gson = gson; this.spaceWrapper = spaceWrapper; this.customTypesMap = customTypesMap; + this.nullifyUnresolved = nullifyUnresolved; } } diff --git a/src/test/kotlin/com/contentful/java/cda/BaseTest.kt b/src/test/kotlin/com/contentful/java/cda/BaseTest.kt index 3ad7e193..c8484483 100644 --- a/src/test/kotlin/com/contentful/java/cda/BaseTest.kt +++ b/src/test/kotlin/com/contentful/java/cda/BaseTest.kt @@ -77,6 +77,6 @@ open class BaseTest { fun getServerUrl(): String { val url = server!!.getUrl("/") - return url.toString().substring(url.getProtocol().length + 3) + return url.toString().substring(url.getProtocol().length() + 3) } } diff --git a/src/test/kotlin/com/contentful/java/cda/EntryTests.kt b/src/test/kotlin/com/contentful/java/cda/EntryTests.kt index e711e5aa..a3d85cee 100644 --- a/src/test/kotlin/com/contentful/java/cda/EntryTests.kt +++ b/src/test/kotlin/com/contentful/java/cda/EntryTests.kt @@ -24,11 +24,44 @@ import com.contentful.java.cda.model.CDAEntry import com.contentful.java.cda.model.CDAAsset import com.contentful.java.cda.model.CDAArray import kotlin.test.assertNotNull +import retrofit.RestAdapter +import kotlin.test.assertNull /** * Entry Tests. */ class EntryTests : BaseTest() { + test fun testFetchAllWithUnresolvedLink() { + enqueue("entry_fetch_all_unresolved_link.json") + val entry = client!!.entries().fetchAll().getItems()[0] as CDAEntry + assertTrue(entry.getFields().get("linked") is Map<*, *>) + + val list = entry.getFields().get("linked_list") as List<*> + assertEquals(2, list.size()) + assertTrue(list[0] is Map<*, *>) + } + + test fun testNullifyUnresolvedLinks() { + val cli = CDAClient.Builder() + .setAccessToken("token") + .setSpaceKey("spaceid") + .setEndpoint(getServerUrl()) + .setLogLevel(RestAdapter.LogLevel.FULL) + .nullifyUnresolvedLinks() + .noSSL() + .build() + + enqueue("space_fetch_response.json") + enqueue("entry_fetch_all_unresolved_link.json") + + val entry = cli!!.entries().fetchAll().getItems()[0] as CDAEntry + assertNull(entry.getFields().get("linked")) + + val list = entry.getFields().get("linked_list") as List<*> + assertEquals(1, list.size()) + assertTrue(list[0] is CDAEntry) + } + test fun testCustomClass() { val cli = CDAClient.Builder() .setAccessToken("token") diff --git a/src/test/resources/entry_fetch_all_unresolved_link.json b/src/test/resources/entry_fetch_all_unresolved_link.json new file mode 100644 index 00000000..ea9e77bc --- /dev/null +++ b/src/test/resources/entry_fetch_all_unresolved_link.json @@ -0,0 +1,113 @@ +{ + "sys": { + "type": "Array" + }, + "total": 1, + "skip": 0, + "limit": 100, + "items": [ + { + "sys": { + "space": { + "sys": { + "type": "Link", + "linkType": "Space", + "id": "lsuyo9b7men3" + } + }, + "type": "Entry", + "contentType": { + "sys": { + "type": "Link", + "linkType": "ContentType", + "id": "5HYo9FeMfY6o2Aum4coQug" + } + }, + "id": "3HGy9WXD2USmQsW4Q80ooM", + "revision": 2, + "createdAt": "2014-12-29T16:01:11.114Z", + "updatedAt": "2014-12-29T16:03:38.007Z", + "locale": "en-US" + }, + "fields": { + "f1": "ff", + "mid1": "sdfsdf", + "linked": { + "sys": { + "type": "Link", + "linkType": "Entry", + "id": "3zYq1TBEysU0oQMmMeComi" + } + }, + "linked_list": [ + { + "sys": { + "type": "Link", + "linkType": "Entry", + "id": "3zYq1TBEysU0oQMmMeComi" + } + }, + { + "sys": { + "type": "Link", + "linkType": "Entry", + "id": "doge" + } + } + ] + } + } + ], + "includes": { + "Entry": [ + { + "sys": { + "space": { + "sys": { + "type": "Link", + "linkType": "Space", + "id": "cfexampleapi" + } + }, + "type": "Entry", + "contentType": { + "sys": { + "type": "Link", + "linkType": "ContentType", + "id": "dog" + } + }, + "id": "doge", + "revision": 2, + "createdAt": "2013-11-06T09:45:27.475Z", + "updatedAt": "2013-11-18T09:13:37.808Z", + "locale": "en-US" + }, + "fields": { + "name": "Doge", + "image": { + "sys": { + "type": "Link", + "linkType": "Asset", + "id": "1x0xpXu4pSGS4OukSyWGUK" + } + }, + "description": "such json\nwow" + } + } + ] + }, + "errors": [ + { + "sys": { + "type": "error", + "id": "notResolvable" + }, + "details": { + "type": "Link", + "linkType": "Entry", + "id": "3zYq1TBEysU0oQMmMeComi" + } + } + ] +} \ No newline at end of file