From c57b160a5b702b5120e9cf5b484d035ae59efd88 Mon Sep 17 00:00:00 2001 From: Aleksei Averchenko Date: Mon, 27 Apr 2026 17:29:29 +0100 Subject: [PATCH 1/3] Fixed the `Comment` parsing errors when the `type` field is absent --- src/main/java/org/zendesk/client/v2/model/Comment.java | 9 ++++++++- .../zendesk/client/v2/model/comments/VoiceComment.java | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/zendesk/client/v2/model/Comment.java b/src/main/java/org/zendesk/client/v2/model/Comment.java index 3be296ba..17691e1a 100644 --- a/src/main/java/org/zendesk/client/v2/model/Comment.java +++ b/src/main/java/org/zendesk/client/v2/model/Comment.java @@ -3,6 +3,7 @@ import static com.fasterxml.jackson.annotation.JsonTypeInfo.As.EXTERNAL_PROPERTY; import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -16,12 +17,18 @@ * @author stephenc * @since 09/04/2013 15:09 */ -@JsonTypeInfo(use = NAME, include = EXTERNAL_PROPERTY, property = "type", visible = true) +@JsonTypeInfo( + use = NAME, + include = EXTERNAL_PROPERTY, + property = "type", + defaultImpl = Comment.class, + visible = true) @JsonSubTypes({ @JsonSubTypes.Type(value = Comment.class, name = "Comment"), @JsonSubTypes.Type(value = VoiceComment.class, name = "VoiceComment"), @JsonSubTypes.Type(value = VoiceComment.class, name = "TpeVoiceComment") }) +@JsonIgnoreProperties(ignoreUnknown = true) public class Comment implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/zendesk/client/v2/model/comments/VoiceComment.java b/src/main/java/org/zendesk/client/v2/model/comments/VoiceComment.java index 5afaed22..68bed764 100644 --- a/src/main/java/org/zendesk/client/v2/model/comments/VoiceComment.java +++ b/src/main/java/org/zendesk/client/v2/model/comments/VoiceComment.java @@ -1,8 +1,10 @@ package org.zendesk.client.v2.model.comments; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.zendesk.client.v2.model.Comment; +@JsonIgnoreProperties(ignoreUnknown = true) public class VoiceComment extends Comment { private VoiceCommentData data; From f8a435ff57d77c0528dc0227772151d5c64b0bf9 Mon Sep 17 00:00:00 2001 From: Aleksei Averchenko Date: Mon, 27 Apr 2026 18:10:41 +0100 Subject: [PATCH 2/3] Added tests --- .../zendesk/client/v2/model/CommentTest.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/test/java/org/zendesk/client/v2/model/CommentTest.java diff --git a/src/test/java/org/zendesk/client/v2/model/CommentTest.java b/src/test/java/org/zendesk/client/v2/model/CommentTest.java new file mode 100644 index 00000000..aadfdfaf --- /dev/null +++ b/src/test/java/org/zendesk/client/v2/model/CommentTest.java @@ -0,0 +1,99 @@ +package org.zendesk.client.v2.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.function.Function; +import org.jetbrains.annotations.Nullable; +import org.junit.Test; +import org.zendesk.client.v2.Zendesk; +import org.zendesk.client.v2.model.comments.VoiceComment; + +public class CommentTest { + + private static final long COMMENT_ID = 123L; + private static final String COMMENT_BODY = "Foo"; + private static final String COMMENT_VOICE_URL = "http://yourdomain.com/recordings/1.mp3"; + + private static final ObjectMapper MAPPER = Zendesk.createMapper(Function.identity()); + + @Test + public void defaultType() throws JsonProcessingException { + String json = createCommentJson(null); + Comment comment = parseJson(json); + assertEquals(Comment.class, comment.getClass()); + assertEquals(Long.valueOf(COMMENT_ID), comment.getId()); + assertEquals(COMMENT_BODY, comment.getBody()); + } + + @Test + public void explicitTypeComment() throws JsonProcessingException { + String json = createCommentJson("Comment"); + Comment comment = parseJson(json); + assertEquals(Comment.class, comment.getClass()); + assertEquals(Long.valueOf(COMMENT_ID), comment.getId()); + assertEquals(COMMENT_BODY, comment.getBody()); + } + + @Test + public void explicitTypeVoiceComment() throws JsonProcessingException { + String json = createCommentJson("VoiceComment"); + Comment comment = parseJson(json); + assertEquals(VoiceComment.class, comment.getClass()); + + VoiceComment voiceComment = (VoiceComment) comment; + assertEquals(Long.valueOf(COMMENT_ID), voiceComment.getId()); + assertEquals(COMMENT_BODY, voiceComment.getBody()); + assertEquals(COMMENT_VOICE_URL, voiceComment.getData().getRecordingUrl()); + } + + @Test + public void explicitTypeTpeVoiceCommentType() throws JsonProcessingException { + String json = createCommentJson("TpeVoiceComment"); + Comment comment = parseJson(json); + assertEquals(VoiceComment.class, comment.getClass()); + + VoiceComment voiceComment = (VoiceComment) comment; + assertEquals(Long.valueOf(COMMENT_ID), voiceComment.getId()); + assertEquals(COMMENT_BODY, voiceComment.getBody()); + assertEquals(COMMENT_VOICE_URL, voiceComment.getData().getRecordingUrl()); + } + + @Test + public void invalidType() throws JsonProcessingException { + String json = createCommentJson("InvalidCommentType"); + assertThrows(InvalidFormatException.class, () -> parseJson(json)); + } + + private static String createCommentJson(@Nullable String type) throws JsonProcessingException { + // https://developer.zendesk.com/documentation/ticketing/managing-tickets/adding-voice-comments-to-tickets/ + ObjectNode voiceData = MAPPER.createObjectNode() + .put("from", "+16617480240") + .put("to", "+16617480123") + .put("recording_url", COMMENT_VOICE_URL) + .put("started_at", "2019-04-16T09:14:57Z") + .put("call_duration", 42) + .put("answered_by_id", 28765) + .put("transcription_text", "The transcription of the call") + .put("location", "Topeka, Kansas"); + + ObjectNode res = MAPPER.createObjectNode() + .put("id", COMMENT_ID) + .put("body", "Foo") + .set("data", voiceData); + + if (type != null) { + res.put("type", type); + } + + return MAPPER.writeValueAsString(res); + } + + private static Comment parseJson(String json) throws JsonProcessingException { + return MAPPER.readValue(json, Comment.class); + } +} From d48604cab9f663939a458d8a0a03a3f65e4cd013 Mon Sep 17 00:00:00 2001 From: Pierre Beitz Date: Tue, 5 May 2026 15:09:42 +0200 Subject: [PATCH 3/3] fix format --- .../zendesk/client/v2/model/CommentTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/test/java/org/zendesk/client/v2/model/CommentTest.java b/src/test/java/org/zendesk/client/v2/model/CommentTest.java index aadfdfaf..a1bf77f8 100644 --- a/src/test/java/org/zendesk/client/v2/model/CommentTest.java +++ b/src/test/java/org/zendesk/client/v2/model/CommentTest.java @@ -71,20 +71,20 @@ public void invalidType() throws JsonProcessingException { private static String createCommentJson(@Nullable String type) throws JsonProcessingException { // https://developer.zendesk.com/documentation/ticketing/managing-tickets/adding-voice-comments-to-tickets/ - ObjectNode voiceData = MAPPER.createObjectNode() - .put("from", "+16617480240") - .put("to", "+16617480123") - .put("recording_url", COMMENT_VOICE_URL) - .put("started_at", "2019-04-16T09:14:57Z") - .put("call_duration", 42) - .put("answered_by_id", 28765) - .put("transcription_text", "The transcription of the call") - .put("location", "Topeka, Kansas"); - - ObjectNode res = MAPPER.createObjectNode() - .put("id", COMMENT_ID) - .put("body", "Foo") - .set("data", voiceData); + ObjectNode voiceData = + MAPPER + .createObjectNode() + .put("from", "+16617480240") + .put("to", "+16617480123") + .put("recording_url", COMMENT_VOICE_URL) + .put("started_at", "2019-04-16T09:14:57Z") + .put("call_duration", 42) + .put("answered_by_id", 28765) + .put("transcription_text", "The transcription of the call") + .put("location", "Topeka, Kansas"); + + ObjectNode res = + MAPPER.createObjectNode().put("id", COMMENT_ID).put("body", "Foo").set("data", voiceData); if (type != null) { res.put("type", type);