From 9cadacf4b7db924921978eee0618d01740c71bbb Mon Sep 17 00:00:00 2001 From: Gordan Ovcaric Date: Wed, 29 Apr 2026 14:41:54 +0200 Subject: [PATCH] TW-3961: include grantID in get folders response --- .claude/instructions.md | 17 +++++++++++ .claude/settings.local.json | 4 ++- CHANGELOG.md | 5 ++++ src/main/kotlin/com/nylas/models/Folder.kt | 4 +-- .../com/nylas/resources/FoldersTests.kt | 28 +++++++++++++++++++ 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/.claude/instructions.md b/.claude/instructions.md index 6eebb70c..c8683fe5 100644 --- a/.claude/instructions.md +++ b/.claude/instructions.md @@ -9,6 +9,23 @@ Your job is to maintain parity with the API to ensure that the SDK supports all When asked to add support for a new feature, query parameter, or API endpoint, follow this workflow: +### 0. Analyse Backward Compatibility FIRST (before proposing any plan) + +Before writing a plan or touching any code, explicitly analyse whether the proposed changes are backward compatible for existing SDK consumers (both Kotlin and Java). + +Check all of the following: +- **Source compatibility (Kotlin)**: Does changing a type (e.g. `String` → `String?`) break existing call sites that assume non-nullability? +- **Source compatibility (Java)**: Does the change affect compiled Java code that uses the SDK? +- **Binary compatibility (JVM)**: Does the bytecode signature of any public method change? +- **Constructor/data class compatibility**: Does changing a field's type or default break existing construction patterns? + +If the change is **NOT** backward compatible, output this warning in your response before anything else: + +> # ⚠️ WARNING: THIS CHANGE IS NOT BACKWARD COMPATIBLE ⚠️ +> Existing SDK consumers will be broken. Do not proceed without explicit user approval or a backward-compatible alternative. + +If a backward-compatible alternative exists (e.g. using `String = ""` instead of `String?` to keep Moshi happy while preserving non-nullability), prefer it and explain why. + ### 1. Understand the Codebase - Scan the project structure - Understand the architecture and how it's organized diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 0165ab35..d2f14873 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -12,7 +12,9 @@ "Bash(/usr/libexec/java_home:*)", "Bash(./gradlew clean test:*)", "Bash(./gradlew:*)", - "Bash(./gradlew build:*)" + "Bash(./gradlew build:*)", + "mcp__claude_ai_Atlassian__getJiraIssue", + "WebFetch(domain:developer.nylas.com)" ] } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d0b090f..3f2adb2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Nylas Java SDK Changelog +## [Unreleased] + +### Fixed +* `Folder.id` and `Folder.grantId` now default to empty strings so deserialization no longer fails when either field is absent from the API response due to the `select` query parameter + ## [v2.15.1] - Release 2026-03-30 ### Changed diff --git a/src/main/kotlin/com/nylas/models/Folder.kt b/src/main/kotlin/com/nylas/models/Folder.kt index bcac524d..4b44f6ae 100644 --- a/src/main/kotlin/com/nylas/models/Folder.kt +++ b/src/main/kotlin/com/nylas/models/Folder.kt @@ -10,12 +10,12 @@ data class Folder( * A globally unique object identifier. */ @Json(name = "id") - val id: String, + val id: String = "", /** * A Grant ID of the Nylas account. */ @Json(name = "grant_id") - val grantId: String, + val grantId: String = "", /** * Folder name */ diff --git a/src/test/kotlin/com/nylas/resources/FoldersTests.kt b/src/test/kotlin/com/nylas/resources/FoldersTests.kt index 3c12f845..479299d4 100644 --- a/src/test/kotlin/com/nylas/resources/FoldersTests.kt +++ b/src/test/kotlin/com/nylas/resources/FoldersTests.kt @@ -75,6 +75,34 @@ class FoldersTests { assertEquals(0, folder.totalCount) assertEquals(listOf("\\SENT"), folder.attributes) } + + @Test + fun `Folder deserializes correctly when grant_id is absent due to select`() { + val adapter = JsonHelper.moshi().adapter(Folder::class.java) + val jsonBuffer = Buffer().writeUtf8( + """{ "id": "SENT", "name": "SENT", "object": "folder" }""", + ) + + val folder = adapter.fromJson(jsonBuffer)!! + assertIs(folder) + assertEquals("SENT", folder.id) + assertEquals("", folder.grantId) + assertEquals("SENT", folder.name) + } + + @Test + fun `Folder deserializes correctly when both id and grant_id are absent due to select`() { + val adapter = JsonHelper.moshi().adapter(Folder::class.java) + val jsonBuffer = Buffer().writeUtf8( + """{ "name": "SENT", "object": "folder" }""", + ) + + val folder = adapter.fromJson(jsonBuffer)!! + assertIs(folder) + assertEquals("", folder.id) + assertEquals("", folder.grantId) + assertEquals("SENT", folder.name) + } } @Nested