From f33b0d0565d5e66e51f3df7d0de0e80fb21961bb Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 17 Mar 2025 15:20:31 +0530 Subject: [PATCH 01/10] Asset pojo implementation --- .../com/contentstack/cms/stack/Asset.java | 33 ++++++++ .../cms/stack/AssetListResponse.java | 32 ++++++++ .../com/contentstack/cms/stack/AssetPojo.java | 77 +++++++++++++++++++ .../contentstack/cms/stack/AssetResponse.java | 27 +++++++ .../contentstack/cms/stack/AssetService.java | 39 +++++++++- 5 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/contentstack/cms/stack/AssetListResponse.java create mode 100644 src/main/java/com/contentstack/cms/stack/AssetPojo.java create mode 100644 src/main/java/com/contentstack/cms/stack/AssetResponse.java diff --git a/src/main/java/com/contentstack/cms/stack/Asset.java b/src/main/java/com/contentstack/cms/stack/Asset.java index 6cd802ae..a2ee4a1c 100644 --- a/src/main/java/com/contentstack/cms/stack/Asset.java +++ b/src/main/java/com/contentstack/cms/stack/Asset.java @@ -60,6 +60,7 @@ protected Asset(Retrofit instance, Map header, String uid) { * object as its value. * @return instance of Asset */ + @Override public Asset addParam(@NotNull String key, @NotNull Object value) { this.params.put(key, value); return this; @@ -74,6 +75,7 @@ public Asset addParam(@NotNull String key, @NotNull Object value) { * header. * @return instance of Asset */ + @Override public Asset addHeader(@NotNull String key, @NotNull String value) { this.headers.put(key, value); return this; @@ -86,6 +88,7 @@ public Asset addHeader(@NotNull String key, @NotNull String value) { * representing the header value. * @return instance of Asset */ + @Override public Asset addHeaders(@NotNull HashMap headers) { this.headers.putAll(headers); return this; @@ -98,6 +101,7 @@ public Asset addHeaders(@NotNull HashMap headers) { * annotated with @NotNull, indicating that it cannot be null. * @return instance of Asset */ + @Override public Asset addParams(@NotNull HashMap headers) { this.params.putAll(headers); return this; @@ -198,6 +202,10 @@ public Call find() { return this.service.fetch(this.headers, this.params); } + public Call findAsPojo() { + return this.service.fetchPojo(this.headers, this.params); + } + /** * The Get an asset call returns comprehensive information about a specific * version of an asset of a stack @@ -221,6 +229,11 @@ public Call fetch() { return this.service.single(this.headers, this.assetUid, this.params); } + public Call fetchAsPojo() { // New method for POJO conversion + Objects.requireNonNull(this.assetUid, "Asset Uid Can Not Be Null OR Empty"); + return this.service.singlePojo(this.headers, this.assetUid, this.params); + } + /** * The Get assets of a specific folder retrieves all assets of a specific asset * folder; however, it doesn't retrieve @@ -241,6 +254,11 @@ public Call byFolderUid(@NotNull String folderUid) { return this.service.specificFolder(this.headers, this.params); } + public Call byFolderUidAsPojo(@NotNull String folderUid) { + this.params.put("folder", folderUid); + return this.service.specificFolderPojo(this.headers, this.params); + } + /** * The Get assets and folders of a parent folder retrieves details of both * assets and asset sub-folders within a @@ -264,6 +282,13 @@ public Call subfolder( return this.service.subfolder(this.headers, this.params); } + public Call subfolderAsPojo( + @NotNull String folderUid, Boolean isIncludeFolders) { + this.params.put("folder", folderUid); + this.params.put("include_folders", isIncludeFolders); + return this.service.subfolderPojo(this.headers, this.params); +} + /** * The Upload asset request uploads an asset file to your stack. *

@@ -731,6 +756,10 @@ public Call getSingleFolderByName() { return this.service.singleFolderByName(this.headers, this.params); } + public Call getSingleFolderByNameAsPojo() { + return this.service.singleFolderByNamePojo(this.headers, this.params); + } + /** * Get sub-folders of a parent folder request retrieves the details of only the * sub-folders of a specific asset @@ -750,6 +779,10 @@ public Call getSubfolder() { return this.service.getSubfolder(this.headers, this.params); } + public Call getSubfolderAsPojo() { + return this.service.getSubfolderPojo(this.headers, this.params); + } + protected Asset removeParam(String key) { this.params.remove(key); return this; diff --git a/src/main/java/com/contentstack/cms/stack/AssetListResponse.java b/src/main/java/com/contentstack/cms/stack/AssetListResponse.java new file mode 100644 index 00000000..d47fe530 --- /dev/null +++ b/src/main/java/com/contentstack/cms/stack/AssetListResponse.java @@ -0,0 +1,32 @@ +package com.contentstack.cms.stack; + +import java.util.List; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +public class AssetListResponse { + + @SerializedName("assets") + private List> rawJson; + + private transient List assets; + + public List getAssets() { + if (assets == null && rawJson != null) { + assets = new Gson().fromJson(new Gson().toJsonTree(rawJson), new TypeToken>(){}.getType()); + } + return assets; + } + + public List> getRawJson() { + return rawJson; + } + + @Override + public String toString() { + return new com.google.gson.GsonBuilder().setPrettyPrinting().create().toJson(this); + } +} diff --git a/src/main/java/com/contentstack/cms/stack/AssetPojo.java b/src/main/java/com/contentstack/cms/stack/AssetPojo.java new file mode 100644 index 00000000..222617c2 --- /dev/null +++ b/src/main/java/com/contentstack/cms/stack/AssetPojo.java @@ -0,0 +1,77 @@ +package com.contentstack.cms.stack; +import java.util.Map; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class AssetPojo { + + @SerializedName("uid") + private String uid; + + @SerializedName("title") + private String title; + + @SerializedName("content_type") + private String contentType; + + @SerializedName("file_size") + private String fileSize; + + @SerializedName("filename") + private String filename; + + @SerializedName("url") + private String url; + + @SerializedName("description") + private String description; + + @SerializedName("_version") + private int version; + + @SerializedName("is_dir") + private boolean isDir; + + @SerializedName("tags") + private String[] tags; + + @SerializedName("name") + private String name; + + // Store any unknown/dynamic fields + @Expose(serialize = false, deserialize = false) + private transient Map additionalFields; + + public Map getAdditionalFields() { + return additionalFields; + } + + public void setAdditionalFields(Map additionalFields) { + this.additionalFields = additionalFields; + } + + // Getters + public String getUid() { return uid; } + public String getTitle() { + if (contentType.equals("application/vnd.contenstack.folder")) { + return name; + } + return title; } + public String getContentType() { return contentType; } + public String getFileSize() { return fileSize; } + public String getFilename() { return filename; } + public String getUrl() { return url; } + public String getDescription() { return description; } + public int getVersion() { return version; } + public boolean isDir() { return isDir; } + public String[] getTags() { return tags; } + + @Override + public String toString() { + return new com.google.gson.GsonBuilder() + .setPrettyPrinting() + .create() + .toJson(this); + } +} + diff --git a/src/main/java/com/contentstack/cms/stack/AssetResponse.java b/src/main/java/com/contentstack/cms/stack/AssetResponse.java new file mode 100644 index 00000000..bb4edaad --- /dev/null +++ b/src/main/java/com/contentstack/cms/stack/AssetResponse.java @@ -0,0 +1,27 @@ +package com.contentstack.cms.stack; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import java.util.Map; + +public class AssetResponse { + @SerializedName("asset") + private Map rawJson; // Store the full asset JSON + + private AssetPojo assetPojo; + + public AssetPojo getAssetPojo() { + if (assetPojo == null && rawJson != null) { + assetPojo = new Gson().fromJson(new Gson().toJson(rawJson), AssetPojo.class); + } + return assetPojo; + } + public Map getRawJson() { + return rawJson; + } + @Override + public String toString() { + return new com.google.gson.GsonBuilder().setPrettyPrinting().create().toJson(this); + } +} + + diff --git a/src/main/java/com/contentstack/cms/stack/AssetService.java b/src/main/java/com/contentstack/cms/stack/AssetService.java index 5199adeb..512203a0 100644 --- a/src/main/java/com/contentstack/cms/stack/AssetService.java +++ b/src/main/java/com/contentstack/cms/stack/AssetService.java @@ -15,6 +15,11 @@ public interface AssetService { Call fetch( @HeaderMap Map headers, @QueryMap(encoded = true) Map query); + + @GET("assets") + Call fetchPojo( + @HeaderMap Map headers, + @QueryMap(encoded = true) Map query); @GET("assets/{asset_uid}") Call single( @@ -22,16 +27,32 @@ Call single( @Path("asset_uid") String uid, @QueryMap(encoded = true) Map query); + @GET("assets/{asset_uid}") + Call singlePojo( + @HeaderMap Map headers, + @Path("asset_uid") String assetUid, + @QueryMap(encoded = true) Map params); + @GET("assets") Call specificFolder( @HeaderMap Map headers, @QueryMap(encoded = true) Map query); + @GET("assets") + Call specificFolderPojo( + @HeaderMap Map headers, + @QueryMap(encoded = true) Map query); + @GET("assets") Call subfolder( @HeaderMap Map headers, @QueryMap(encoded = true) Map query); + @GET("assets") + Call subfolderPojo( + @HeaderMap Map headers, + @QueryMap(encoded = true) Map query); + @POST("assets") Call uploadAsset( @HeaderMap Map headers, @@ -88,7 +109,7 @@ Call deleteVersionName( @HeaderMap Map headers, @Path("asset_uid") String assetUid, @Path("version_number") int versionNumber); - +// check this if possible to support @GET("assets/{asset_uid}/references") Call getReferences( @HeaderMap Map headers, @@ -124,16 +145,32 @@ Call singleFolder( @Path("folder_uid") String folderUid, @QueryMap Map query); + @GET("assets/folders/{folder_uid}") + Call singleFolderPojo( + @HeaderMap Map headers, + @Path("folder_uid") String folderUid, + @QueryMap Map query); + @GET("assets") Call singleFolderByName( @HeaderMap Map headers, @QueryMap(encoded = true) Map query); + @GET("assets") + Call singleFolderByNamePojo( + @HeaderMap Map headers, + @QueryMap(encoded = true) Map query); + @GET("assets") Call getSubfolder( @HeaderMap Map headers, @QueryMap(encoded = true) Map query); + @GET("assets") + Call getSubfolderPojo( + @HeaderMap Map headers, + @QueryMap(encoded = true) Map query); + @POST("assets/folders") Call createFolder( @HeaderMap Map headers, From d9df6d853d20c6451c8c177506388c7716b1e5c4 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 17 Mar 2025 15:44:24 +0530 Subject: [PATCH 02/10] testcases added --- .../contentstack/cms/stack/AssetAPITest.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/src/test/java/com/contentstack/cms/stack/AssetAPITest.java b/src/test/java/com/contentstack/cms/stack/AssetAPITest.java index 6c38a297..cc149d8d 100644 --- a/src/test/java/com/contentstack/cms/stack/AssetAPITest.java +++ b/src/test/java/com/contentstack/cms/stack/AssetAPITest.java @@ -57,6 +57,7 @@ void testFindAssets() { @Order(2) @Test void testFetch() { + asset = client.stack().asset(_uid); asset.clearParams(); asset.addParam("include_path", false); asset.addParam("version", 1); @@ -265,4 +266,96 @@ void testAssetUploadWithMultipleParams() throws IOException { Assertions.assertFalse(upload.isSuccessful()); } + @Test + void testFetchSingleAssetPojo() throws IOException { + asset = client.stack().asset(_uid) + .addParam("include_count", true); + Request request = asset.fetchAsPojo().request(); + Assertions.assertEquals("GET", request.method()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(443, request.url().port()); + Assertions.assertTrue(request.url().pathSegments().contains("v3")); + Assertions.assertTrue(request.url().pathSegments().contains("assets")); + Assertions.assertEquals( + "https://api.contentstack.io/v3/assets/auth999999999?include_count=true", + request.url().toString()); + } + + @Test + void testFetchAllAssetsPojo() throws IOException { + asset = client.stack().asset(); + Request request = asset.findAsPojo().request(); + Assertions.assertEquals("GET", request.method()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(443, request.url().port()); + Assertions.assertTrue(request.url().pathSegments().contains("v3")); + Assertions.assertTrue(request.url().pathSegments().contains("assets")); + Assertions.assertEquals("https://api.contentstack.io/v3/assets", request.url().toString()); + } + + @Test + void testFetchAssetsByFolderUidPojo() throws IOException { + asset = client.stack().asset(); + Request request = asset.byFolderUidAsPojo("folder_uid").request(); + Assertions.assertEquals("GET", request.method()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(443, request.url().port()); + Assertions.assertTrue(request.url().pathSegments().contains("v3")); + Assertions.assertTrue(request.url().pathSegments().contains("assets")); + Assertions.assertEquals("https://api.contentstack.io/v3/assets?folder=folder_uid", request.url().toString()); + } + + @Test + void testFetchAssetsBySubFolderUidPojo() throws IOException { + asset = client.stack().asset(); + Request request = asset.subfolderAsPojo("subfolder_uid", true).request(); + Assertions.assertEquals("GET", request.method()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(443, request.url().port()); + Assertions.assertTrue(request.url().pathSegments().contains("v3")); + Assertions.assertTrue(request.url().pathSegments().contains("assets")); + Assertions.assertEquals("https://api.contentstack.io/v3/assets?folder=subfolder_uid&include_folders=true", request.url().toString()); + } + + @Test + void testFetchSingleFolderByNamePojo() { + asset = client.stack().asset(); + HashMap queryContent = new HashMap<>(); + queryContent.put("is_dir", true); + queryContent.put("name", "sub_folder_test"); + asset.addParam("query", queryContent); + Request request = asset.getSingleFolderByNameAsPojo().request(); + Assertions.assertEquals("GET", request.method()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(443, request.url().port()); + Assertions.assertTrue(request.url().pathSegments().contains("v3")); + Assertions.assertTrue(request.url().pathSegments().contains("assets")); + Assertions.assertEquals("https://api.contentstack.io/v3/assets?query={is_dir%3Dtrue,%20name%3Dsub_folder_test}", request.url().toString()); + } + + @Test + void testFetchSubfoldersByParentFolderPojo() { + asset = client.stack().asset(); + HashMap queryContent = new HashMap<>(); + queryContent.put("is_dir", true); + asset.addParam("folder", "test_folder"); + asset.addParam("include_folders", true); + asset.addParam("query", queryContent); + queryContent.put("parent_uid", "parent_uid"); + asset.addParam("query", queryContent); + Request request = asset.getSubfolderAsPojo().request(); + Assertions.assertEquals("GET", request.method()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(443, request.url().port()); + Assertions.assertTrue(request.url().pathSegments().contains("v3")); + Assertions.assertTrue(request.url().pathSegments().contains("assets")); + Assertions.assertEquals("https://api.contentstack.io/v3/assets?folder=test_folder&query={parent_uid%3Dparent_uid,%20is_dir%3Dtrue}&include_folders=true", request.url().toString()); + } + } From 11fbdeb147befd6d3ce5a50ff3d8962b1682cebe Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Tue, 25 Mar 2025 13:34:06 +0530 Subject: [PATCH 03/10] removed getter methods for assetpojo --- .../com/contentstack/cms/stack/AssetPojo.java | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/contentstack/cms/stack/AssetPojo.java b/src/main/java/com/contentstack/cms/stack/AssetPojo.java index 222617c2..f5262b99 100644 --- a/src/main/java/com/contentstack/cms/stack/AssetPojo.java +++ b/src/main/java/com/contentstack/cms/stack/AssetPojo.java @@ -6,41 +6,41 @@ public class AssetPojo { @SerializedName("uid") - private String uid; + protected String uid; @SerializedName("title") - private String title; + protected String title; @SerializedName("content_type") - private String contentType; + protected String contentType; @SerializedName("file_size") - private String fileSize; + protected String fileSize; @SerializedName("filename") - private String filename; + protected String filename; @SerializedName("url") - private String url; + protected String url; @SerializedName("description") - private String description; + protected String description; @SerializedName("_version") - private int version; + protected int version; @SerializedName("is_dir") - private boolean isDir; + protected boolean isDir; @SerializedName("tags") - private String[] tags; + protected String[] tags; @SerializedName("name") - private String name; + protected String name; // Store any unknown/dynamic fields @Expose(serialize = false, deserialize = false) - private transient Map additionalFields; + protected transient Map additionalFields; public Map getAdditionalFields() { return additionalFields; @@ -51,20 +51,11 @@ public void setAdditionalFields(Map additionalFields) { } // Getters - public String getUid() { return uid; } public String getTitle() { if (contentType.equals("application/vnd.contenstack.folder")) { return name; } return title; } - public String getContentType() { return contentType; } - public String getFileSize() { return fileSize; } - public String getFilename() { return filename; } - public String getUrl() { return url; } - public String getDescription() { return description; } - public int getVersion() { return version; } - public boolean isDir() { return isDir; } - public String[] getTags() { return tags; } @Override public String toString() { From 4eccf7bd355fa8fd20a00c2c25659d9452030a47 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Tue, 25 Mar 2025 13:42:19 +0530 Subject: [PATCH 04/10] removed additional field methods --- .../com/contentstack/cms/stack/AssetPojo.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/main/java/com/contentstack/cms/stack/AssetPojo.java b/src/main/java/com/contentstack/cms/stack/AssetPojo.java index f5262b99..5a3fb6b7 100644 --- a/src/main/java/com/contentstack/cms/stack/AssetPojo.java +++ b/src/main/java/com/contentstack/cms/stack/AssetPojo.java @@ -1,6 +1,4 @@ package com.contentstack.cms.stack; -import java.util.Map; -import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; public class AssetPojo { @@ -38,18 +36,7 @@ public class AssetPojo { @SerializedName("name") protected String name; - // Store any unknown/dynamic fields - @Expose(serialize = false, deserialize = false) - protected transient Map additionalFields; - - public Map getAdditionalFields() { - return additionalFields; - } - - public void setAdditionalFields(Map additionalFields) { - this.additionalFields = additionalFields; - } - + // Getters public String getTitle() { if (contentType.equals("application/vnd.contenstack.folder")) { From f0b3886b3ceff169f0fa6a73418477c6c7e24392 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Tue, 25 Mar 2025 13:46:14 +0530 Subject: [PATCH 05/10] removed toString redundant method --- src/main/java/com/contentstack/cms/stack/AssetPojo.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/com/contentstack/cms/stack/AssetPojo.java b/src/main/java/com/contentstack/cms/stack/AssetPojo.java index 5a3fb6b7..dd038b1f 100644 --- a/src/main/java/com/contentstack/cms/stack/AssetPojo.java +++ b/src/main/java/com/contentstack/cms/stack/AssetPojo.java @@ -35,7 +35,6 @@ public class AssetPojo { @SerializedName("name") protected String name; - // Getters public String getTitle() { @@ -44,12 +43,5 @@ public String getTitle() { } return title; } - @Override - public String toString() { - return new com.google.gson.GsonBuilder() - .setPrettyPrinting() - .create() - .toJson(this); - } } From 291f48d2377d6495735351452f1923651369d406 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Tue, 25 Mar 2025 15:06:42 +0530 Subject: [PATCH 06/10] =?UTF-8?q?=E2=9C=A8feat:=20POJO=20support=20for=20C?= =?UTF-8?q?ontent=20Types=20and=20update=20the=20ContentTypeService=20to?= =?UTF-8?q?=20support=20POJOs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../contentstack/cms/stack/ContentType.java | 9 ++++++ .../cms/stack/ContentTypePojo.java | 29 +++++++++++++++++ .../cms/stack/ContentTypeResponse.java | 27 ++++++++++++++++ .../cms/stack/ContentTypeService.java | 11 +++++++ .../cms/stack/ContentTypesResponse.java | 31 +++++++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 src/main/java/com/contentstack/cms/stack/ContentTypePojo.java create mode 100644 src/main/java/com/contentstack/cms/stack/ContentTypeResponse.java create mode 100644 src/main/java/com/contentstack/cms/stack/ContentTypesResponse.java diff --git a/src/main/java/com/contentstack/cms/stack/ContentType.java b/src/main/java/com/contentstack/cms/stack/ContentType.java index c26de5a2..cbd36912 100644 --- a/src/main/java/com/contentstack/cms/stack/ContentType.java +++ b/src/main/java/com/contentstack/cms/stack/ContentType.java @@ -195,6 +195,10 @@ public Entry entry(@NotNull String entryUid) { public Call find() { return service.fetch(this.headers, this.params); } + + public Call findAsPojo() { + return service.fetchPojo(this.headers, this.params); + } /** * Get Single Content Type @@ -248,6 +252,11 @@ public Call fetch() { return service.single(this.headers, this.contentTypeUid, this.params); } + public Call fetchAsPojo() { + Objects.requireNonNull(this.contentTypeUid, "Content Type Uid Is Required"); + return service.singlePojo(this.headers, this.contentTypeUid, this.params); + } + /** * Create Content Type *

diff --git a/src/main/java/com/contentstack/cms/stack/ContentTypePojo.java b/src/main/java/com/contentstack/cms/stack/ContentTypePojo.java new file mode 100644 index 00000000..5ae1e286 --- /dev/null +++ b/src/main/java/com/contentstack/cms/stack/ContentTypePojo.java @@ -0,0 +1,29 @@ +package com.contentstack.cms.stack; +import java.util.Map; +import org.json.simple.JSONArray; +import com.google.gson.annotations.SerializedName; + +public class ContentTypePojo { + + @SerializedName("title") + protected String title; + + @SerializedName("uid") + protected String uid; + + @SerializedName("schema") + protected JSONArray schema; + + @SerializedName("field_rules") + protected JSONArray fieldRules; + + @SerializedName("_version") + protected int version; + + @SerializedName("description") + protected String description; + + @SerializedName("options") + protected Map options; + +} diff --git a/src/main/java/com/contentstack/cms/stack/ContentTypeResponse.java b/src/main/java/com/contentstack/cms/stack/ContentTypeResponse.java new file mode 100644 index 00000000..3c5626e1 --- /dev/null +++ b/src/main/java/com/contentstack/cms/stack/ContentTypeResponse.java @@ -0,0 +1,27 @@ +package com.contentstack.cms.stack; + +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class ContentTypeResponse { + @SerializedName("content_type") + private Map rawJson; // Store the full contentType JSON + + private ContentTypePojo contentPojo; + + public ContentTypePojo getContentPojo() { + if (contentPojo == null && rawJson != null) { + contentPojo = new Gson().fromJson(new Gson().toJson(rawJson), ContentTypePojo.class); + } + return contentPojo; + } + public Map getRawJson() { + return rawJson; + } + @Override + public String toString() { + return new com.google.gson.GsonBuilder().setPrettyPrinting().create().toJson(this); + } +} diff --git a/src/main/java/com/contentstack/cms/stack/ContentTypeService.java b/src/main/java/com/contentstack/cms/stack/ContentTypeService.java index 6da06e64..6b3074cb 100644 --- a/src/main/java/com/contentstack/cms/stack/ContentTypeService.java +++ b/src/main/java/com/contentstack/cms/stack/ContentTypeService.java @@ -14,12 +14,23 @@ Call fetch( @HeaderMap Map headers, @QueryMap Map query); + @GET("content_types") + Call fetchPojo( + @HeaderMap Map headers, + @QueryMap Map query); + @GET("content_types/{content_type_uid}") Call single( @HeaderMap Map headers, @Path("content_type_uid") String contentTypeUid, @QueryMap Map queryParam); + @GET("content_types/{content_type_uid}") + Call singlePojo( + @HeaderMap Map headers, + @Path("content_type_uid") String contentTypeUid, + @QueryMap Map queryParam); + @POST("content_types") Call create( @HeaderMap Map headers, diff --git a/src/main/java/com/contentstack/cms/stack/ContentTypesResponse.java b/src/main/java/com/contentstack/cms/stack/ContentTypesResponse.java new file mode 100644 index 00000000..f3f9e1ea --- /dev/null +++ b/src/main/java/com/contentstack/cms/stack/ContentTypesResponse.java @@ -0,0 +1,31 @@ +package com.contentstack.cms.stack; + +import java.util.List; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +public class ContentTypesResponse { + @SerializedName("content_types") + private List> rawJson; + + private transient List contentTypes; + + public List getContentTypes() { + if (contentTypes == null && rawJson != null) { + contentTypes = new Gson().fromJson(new Gson().toJsonTree(rawJson), new TypeToken>(){}.getType()); + } + return contentTypes; + } + + public List> getRawJson() { + return rawJson; + } + + @Override + public String toString() { + return new com.google.gson.GsonBuilder().setPrettyPrinting().create().toJson(this); + } +} From 5947cafcc44086f5408b9cee405106bbd92d4a63 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Tue, 25 Mar 2025 16:00:16 +0530 Subject: [PATCH 07/10] testcases added --- .../cms/stack/ContentTypeAPITest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/test/java/com/contentstack/cms/stack/ContentTypeAPITest.java b/src/test/java/com/contentstack/cms/stack/ContentTypeAPITest.java index 3dda2538..3e58376b 100644 --- a/src/test/java/com/contentstack/cms/stack/ContentTypeAPITest.java +++ b/src/test/java/com/contentstack/cms/stack/ContentTypeAPITest.java @@ -1,12 +1,20 @@ package com.contentstack.cms.stack; +import java.io.IOException; +import java.util.List; + +import com.contentstack.cms.Contentstack; import com.contentstack.cms.TestClient; import com.contentstack.cms.Utils; import com.contentstack.cms.core.Util; + import okhttp3.Request; + import org.json.simple.JSONObject; import org.junit.jupiter.api.*; +import retrofit2.Response; + @Tag("unit") @TestInstance(TestInstance.Lifecycle.PER_CLASS) class ContentTypeAPITest { @@ -272,4 +280,42 @@ void testDeleteForcefully() { Assertions.assertEquals("https://api.contentstack.io/v3/content_types/contentType", request.url().toString()); } + @Test + void testcontentPojo() throws IOException { + contentType = stack.contentType(contentTypeUid); + Request request = contentType.fetchAsPojo().request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("content_types", request.url().pathSegments().get(1)); + Assertions.assertNull(request.url().encodedQuery()); + Assertions.assertEquals("https://api.contentstack.io/v3/content_types/contentType", request.url().toString()); + } + + @Test + void testcontentPojoList() throws IOException { + contentType = stack.contentType(contentTypeUid); + contentType.addParam("include_count", true); + contentType.addParam("include_global_field_schema", true); + + Request request = contentType.findAsPojo().request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(2, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("content_types", request.url().pathSegments().get(1)); + Assertions.assertNotNull(request.url().encodedQuery()); + Assertions.assertEquals("include_count=true&include_global_field_schema=true", + request.url().query().toString()); + Assertions.assertEquals( + "https://api.contentstack.io/v3/content_types?include_count=true&include_global_field_schema=true", + request.url().toString()); + + } + } From 020e1a5c64314931e43151638fc0fe91316d4eb0 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 7 Apr 2025 14:08:21 +0530 Subject: [PATCH 08/10] =?UTF-8?q?=E2=9C=A8feat:=20Add=20POJO=20support=20f?= =?UTF-8?q?or=20Entry=20and=20EntryListResponse,=20including=20fetch=20met?= =?UTF-8?q?hods=20in=20EntryService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/contentstack/cms/stack/Entry.java | 10 ++++ .../cms/stack/EntryListResponse.java | 46 ++++++++++++++++ .../com/contentstack/cms/stack/EntryPojo.java | 52 +++++++++++++++++++ .../contentstack/cms/stack/EntryResponse.java | 44 ++++++++++++++++ .../contentstack/cms/stack/EntryService.java | 21 ++++++++ 5 files changed, 173 insertions(+) create mode 100644 src/main/java/com/contentstack/cms/stack/EntryListResponse.java create mode 100644 src/main/java/com/contentstack/cms/stack/EntryPojo.java create mode 100644 src/main/java/com/contentstack/cms/stack/EntryResponse.java diff --git a/src/main/java/com/contentstack/cms/stack/Entry.java b/src/main/java/com/contentstack/cms/stack/Entry.java index 8fb6d88e..818229a9 100644 --- a/src/main/java/com/contentstack/cms/stack/Entry.java +++ b/src/main/java/com/contentstack/cms/stack/Entry.java @@ -189,6 +189,11 @@ public Call find() { return this.service.fetch(this.headers, this.contentTypeUid, this.params); } + public Call findAsPojo() { + validateCT(); + return this.service.fetchPojo(this.headers, this.contentTypeUid, this.params); + } + /** * The Get a single entry request fetches a particular entry of a content * type. @@ -214,6 +219,11 @@ public Call fetch() { validateEntry(); return this.service.single(headers, this.contentTypeUid, this.entryUid, this.params); } + public Call fetchAsPojo() { + validateCT(); + validateEntry(); + return this.service.singlePojo(headers, this.contentTypeUid, this.entryUid, this.params); + } /** * The Create an entry call creates a new entry for the selected content type. diff --git a/src/main/java/com/contentstack/cms/stack/EntryListResponse.java b/src/main/java/com/contentstack/cms/stack/EntryListResponse.java new file mode 100644 index 00000000..d41c5e36 --- /dev/null +++ b/src/main/java/com/contentstack/cms/stack/EntryListResponse.java @@ -0,0 +1,46 @@ +package com.contentstack.cms.stack; +import com.google.gson.annotations.SerializedName; +import com.google.gson.JsonObject; +import com.google.gson.JsonElement; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.util.*; + +public class EntryListResponse { + + @SerializedName("entries") + private List rawEntries; + + private transient List entries; + + public List getEntries() { + if (entries == null && rawEntries != null) { + Gson gson = new Gson(); + entries = new ArrayList<>(); + + for (JsonObject entryJson : rawEntries) { + EntryPojo entryPojo = gson.fromJson(entryJson, EntryPojo.class); + // Map dynamic fields + Map fields = new LinkedHashMap<>(); + for (Map.Entry field : entryJson.entrySet()) { + String key = field.getKey(); + if (!EntryPojo.SYSTEM_FIELDS.contains(key)) { + fields.put(key, gson.fromJson(field.getValue(), Object.class)); + } + } + entryPojo.setFields(fields); + entries.add(entryPojo); + } + } + return entries; + } + + public List getRawJson() { + return rawEntries; + } + + @Override + public String toString() { + return new GsonBuilder().setPrettyPrinting().create().toJson(this); + } +} diff --git a/src/main/java/com/contentstack/cms/stack/EntryPojo.java b/src/main/java/com/contentstack/cms/stack/EntryPojo.java new file mode 100644 index 00000000..9e97a295 --- /dev/null +++ b/src/main/java/com/contentstack/cms/stack/EntryPojo.java @@ -0,0 +1,52 @@ +package com.contentstack.cms.stack; +import java.util.Map; +import java.util.Set; +import java.util.HashSet; +import java.util.Arrays; +import com.google.gson.annotations.SerializedName; + +public class EntryPojo { + + @SerializedName("title") + public String title; + + @SerializedName("uid") + public String uid; + + @SerializedName("_version") + public int version; + + @SerializedName("locale") + public String locale; + + // Additional fields captured dynamically from content type schema + protected Map fields; + + public Map getFields() { + return fields; + } + + public void setFields(Map fields) { + this.fields = fields; + } + + public String getStringField(String key) { + Object value = fields.get(key); + return value != null ? value.toString() : null; + } + + public Map getJsonObjectField(String key) { + Object value = fields.get(key); + if (value instanceof Map) { + return (Map) value; + } + return null; + } + // Define system fields to exclude from dynamic mapping + public static final Set SYSTEM_FIELDS = new HashSet<>(Arrays.asList( + "title","uid", "_version", "locale", "tags", "ACL", "created_by", "updated_by", + "created_at", "updated_at", "_in_progress" + )); +} + + diff --git a/src/main/java/com/contentstack/cms/stack/EntryResponse.java b/src/main/java/com/contentstack/cms/stack/EntryResponse.java new file mode 100644 index 00000000..c9acc5c8 --- /dev/null +++ b/src/main/java/com/contentstack/cms/stack/EntryResponse.java @@ -0,0 +1,44 @@ +package com.contentstack.cms.stack; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class EntryResponse { + + @SerializedName("entry") + private JsonObject entryJson; + + private EntryPojo entryPojo; + + public EntryPojo getEntryPojo() { + if (entryPojo == null && entryJson != null) { + Gson gson = new Gson(); + // Deserialize system fields automatically + entryPojo = gson.fromJson(entryJson, EntryPojo.class); + // Manually extract and map only non-system (dynamic) fields + Map fields = new LinkedHashMap<>(); + for (Map.Entry entry : entryJson.entrySet()) { + String key = entry.getKey(); + if (!EntryPojo.SYSTEM_FIELDS.contains(key)) { + fields.put(key, gson.fromJson(entry.getValue(), Object.class)); + } + } + entryPojo.setFields(fields); + } + return entryPojo; + } + + public JsonObject getRawJson() { + return entryJson; + } + + @Override + public String toString() { + return new GsonBuilder().setPrettyPrinting().create().toJson(this); + } +} diff --git a/src/main/java/com/contentstack/cms/stack/EntryService.java b/src/main/java/com/contentstack/cms/stack/EntryService.java index 83f54d8a..959fbc61 100644 --- a/src/main/java/com/contentstack/cms/stack/EntryService.java +++ b/src/main/java/com/contentstack/cms/stack/EntryService.java @@ -16,6 +16,12 @@ Call fetch( @Path("content_type_uid") String contentTypeUid, @QueryMap(encoded = true) Map queryParameter); + @GET("content_types/{content_type_uid}/entries") + Call fetchPojo( + @HeaderMap Map headers, + @Path("content_type_uid") String contentTypeUid, + @QueryMap(encoded = true) Map queryParameter); + @Headers("Content-Type: application/json") @GET("content_types/{content_type_uid}/entries/{entry_uid}") Call single( @@ -24,6 +30,14 @@ Call single( @Path("entry_uid") String entryUid, @QueryMap(encoded = true) Map queryParameter); + @Headers("Content-Type: application/json") + @GET("content_types/{content_type_uid}/entries/{entry_uid}") + Call singlePojo( + @HeaderMap Map headers, + @Path("content_type_uid") String contentTypeUid, + @Path("entry_uid") String entryUid, + @QueryMap(encoded = true) Map queryParameter); + @Headers("Content-Type: application/json") @POST("content_types/{content_type_uid}/entries") Call create( @@ -115,6 +129,13 @@ Call export( @Path("entry_uid") String entryUid, @QueryMap(encoded = true) Map queryOptions); + @GET("content_types/{content_type_uid}/entries/{entry_uid}/export") + Call exportPojo( + @HeaderMap Map headers, + @Path("content_type_uid") String contentTypeUid, + @Path("entry_uid") String entryUid, + @QueryMap(encoded = true) Map queryOptions); + @POST("content_types/{content_type_uid}/entries/import") Call imports( @HeaderMap Map headers, From 0ece770b2f0d6c2b7d22fa864487399aa35cb941 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 7 Apr 2025 16:25:11 +0530 Subject: [PATCH 09/10] =?UTF-8?q?=F0=9F=94=A7refactor:=20Remove=20unused?= =?UTF-8?q?=20exportPojo=20method=20from=20EntryService=20interface?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/contentstack/cms/stack/EntryService.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/com/contentstack/cms/stack/EntryService.java b/src/main/java/com/contentstack/cms/stack/EntryService.java index 959fbc61..8c5c82fb 100644 --- a/src/main/java/com/contentstack/cms/stack/EntryService.java +++ b/src/main/java/com/contentstack/cms/stack/EntryService.java @@ -129,13 +129,6 @@ Call export( @Path("entry_uid") String entryUid, @QueryMap(encoded = true) Map queryOptions); - @GET("content_types/{content_type_uid}/entries/{entry_uid}/export") - Call exportPojo( - @HeaderMap Map headers, - @Path("content_type_uid") String contentTypeUid, - @Path("entry_uid") String entryUid, - @QueryMap(encoded = true) Map queryOptions); - @POST("content_types/{content_type_uid}/entries/import") Call imports( @HeaderMap Map headers, From 5b3141e5cff65708bdf43a6a2ebf4c5c5a99094d Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 7 Apr 2025 16:54:08 +0530 Subject: [PATCH 10/10] =?UTF-8?q?=E2=9C=A8test:=20Add=20POJO=20tests=20for?= =?UTF-8?q?=20Entry=20and=20EntryListResponse=20fetching=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cms/stack/EntryFieldsAPITest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/test/java/com/contentstack/cms/stack/EntryFieldsAPITest.java b/src/test/java/com/contentstack/cms/stack/EntryFieldsAPITest.java index 3879ba78..c8bbedb1 100644 --- a/src/test/java/com/contentstack/cms/stack/EntryFieldsAPITest.java +++ b/src/test/java/com/contentstack/cms/stack/EntryFieldsAPITest.java @@ -13,6 +13,7 @@ import retrofit2.Response; import java.io.IOException; +import java.util.List; import org.json.simple.JSONArray; import org.json.simple.parser.ParseException; @@ -551,4 +552,42 @@ void testPublishRequest_RejectRequest() throws ParseException { Assertions.assertTrue(request.headers().names().contains("authorization")); } + @Test + void testEntryPojo() throws IOException { + Request request = contentType.entry(API_KEY).fetchAsPojo().request(); + Assertions.assertEquals(3, request.headers().names().size()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(5, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("content_types", request.url().pathSegments().get(1)); + Assertions.assertEquals("test", request.url().pathSegments().get(2)); + Assertions.assertEquals("entries", request.url().pathSegments().get(3)); + Assertions.assertNull(request.url().encodedQuery()); + Assertions.assertEquals( + String.format("https://api.contentstack.io/v3/content_types/test/entries/"+ TestClient.API_KEY), + request.url().toString()); + } + @Test + void testEntryPojoList() throws IOException { + entry.addParam("include_count", true); + entry.addParam("limit", 10); + Request request = entry.findAsPojo().request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals("api.contentstack.io", request.url().host()); + Assertions.assertEquals(4, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("content_types", request.url().pathSegments().get(1)); + Assertions.assertEquals("test", request.url().pathSegments().get(2)); + Assertions.assertEquals("entries", request.url().pathSegments().get(3)); + Assertions.assertNotNull(request.url().encodedQuery()); + Assertions.assertEquals("limit=10&include_count=true", request.url().query().toString()); + Assertions.assertEquals( + String.format("https://api.contentstack.io/v3/content_types/test/entries?limit=10&include_count=true"), + request.url().toString()); + } + }