diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c74b21d..3dde9827 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [4.1.1-top-level-comment-count](https://github.com/GetStream/stream-sdk-java/compare/4.1.1-feed-counts...4.1.1-top-level-comment-count) (2026-09-30) + + +### Features + +* backport top-level comment count onto 4.1.1 ([42504f1](https://github.com/GetStream/stream-sdk-java/commit/42504f1f8d18b6d55e77452b64c9b31899901281)) + +### Bug Fixes + +* read the SDK version from its own jar ([a932c96](https://github.com/GetStream/stream-sdk-java/commit/a932c960ac4600ecba94fe5eca192d28d5601c82)) + ### [4.1.1-feed-counts](https://github.com/GetStream/stream-sdk-java/compare/4.1.1...4.1.1-feed-counts) (2026-09-01) diff --git a/build.gradle.kts b/build.gradle.kts index 606bccb3..b3cc3455 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { implementation(platform("com.squareup.okhttp3:okhttp-bom:4.12.0")) implementation("com.squareup.okhttp3:okhttp") + testImplementation("com.squareup.okhttp3:mockwebserver") implementation("com.fasterxml.jackson.core:jackson-databind:2.18.2") implementation("com.fasterxml.jackson.core:jackson-annotations:2.18.2") implementation("io.jsonwebtoken:jjwt-api:0.12.6") @@ -64,10 +65,14 @@ tasks.named("test") { val generatedVersionDir = layout.buildDirectory.dir("generated-version") +// Not "version.properties" at the jar root. stream-chat-java ships that same name, and +// ClassLoader.getResourceAsStream returns whichever jar comes first. +val sdkVersionResource = "io/getstream/stream-sdk-java/version.properties" + tasks.register("generateVersionProperties") { doLast { - val f = layout.buildDirectory.file("generated-version/version.properties") - val propertiesFile = f.get().asFile + val propertiesFile = + layout.buildDirectory.file("generated-version/$sdkVersionResource").get().asFile propertiesFile.parentFile.mkdirs() val properties = Properties() properties.setProperty("version", version.toString()) diff --git a/gradle.properties b/gradle.properties index c4e6f8d6..9c6ad19f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=4.1.1-feed-counts +version=4.1.1-top-level-comment-count diff --git a/src/main/java/io/getstream/models/ActivityResponse.java b/src/main/java/io/getstream/models/ActivityResponse.java index 34a0ad0c..0abea503 100644 --- a/src/main/java/io/getstream/models/ActivityResponse.java +++ b/src/main/java/io/getstream/models/ActivityResponse.java @@ -132,6 +132,10 @@ public class ActivityResponse { @JsonProperty("text") private String text; + @Nullable + @JsonProperty("top_level_comment_count") + private Integer topLevelCommentCount; + @Nullable @JsonProperty("visibility_tag") private String visibilityTag; diff --git a/src/main/java/io/getstream/models/GetActivityRequest.java b/src/main/java/io/getstream/models/GetActivityRequest.java index 44dab439..d6fc307a 100644 --- a/src/main/java/io/getstream/models/GetActivityRequest.java +++ b/src/main/java/io/getstream/models/GetActivityRequest.java @@ -12,7 +12,16 @@ */ package io.getstream.models; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.getstream.annotations.Query; + @lombok.Data @lombok.Builder @lombok.NoArgsConstructor -public class GetActivityRequest {} +@lombok.AllArgsConstructor +public class GetActivityRequest { + + @Query("include_top_level_comment_count") + @JsonIgnore + private Boolean IncludeTopLevelCommentCount; +} diff --git a/src/main/java/io/getstream/models/GetCommentsRequest.java b/src/main/java/io/getstream/models/GetCommentsRequest.java index d40bcbf4..8982a3ea 100644 --- a/src/main/java/io/getstream/models/GetCommentsRequest.java +++ b/src/main/java/io/getstream/models/GetCommentsRequest.java @@ -52,4 +52,8 @@ public class GetCommentsRequest { @Query("next") @JsonIgnore private String Next; + + @Query("include_top_level_comment_count") + @JsonIgnore + private Boolean IncludeTopLevelCommentCount; } diff --git a/src/main/java/io/getstream/models/GetCommentsResponse.java b/src/main/java/io/getstream/models/GetCommentsResponse.java index 94128146..84fff5a7 100644 --- a/src/main/java/io/getstream/models/GetCommentsResponse.java +++ b/src/main/java/io/getstream/models/GetCommentsResponse.java @@ -22,6 +22,9 @@ @lombok.AllArgsConstructor public class GetCommentsResponse { + @JsonProperty("comment_count") + private Integer commentCount; + @JsonProperty("duration") private String duration; @@ -35,4 +38,8 @@ public class GetCommentsResponse { @Nullable @JsonProperty("prev") private String prev; + + @Nullable + @JsonProperty("top_level_comment_count") + private Integer topLevelCommentCount; } diff --git a/src/main/java/io/getstream/services/framework/StreamHTTPClient.java b/src/main/java/io/getstream/services/framework/StreamHTTPClient.java index 1307d65b..b44118af 100644 --- a/src/main/java/io/getstream/services/framework/StreamHTTPClient.java +++ b/src/main/java/io/getstream/services/framework/StreamHTTPClient.java @@ -88,12 +88,23 @@ public StreamHTTPClient(Properties properties) throws IllegalArgumentException { .compact(); } + // Unique to this jar. A root version.properties collides with stream-chat-java (and any + // other dependency that ships that name): the classloader returns the first match. + private static final String VERSION_RESOURCE = "/io/getstream/stream-sdk-java/version.properties"; + private static @NotNull String readSdkVersion() { - var clsLoader = StreamHTTPClient.class.getClassLoader(); - try (var inputStream = clsLoader.getResourceAsStream("version.properties")) { + try (var inputStream = StreamHTTPClient.class.getResourceAsStream(VERSION_RESOURCE)) { + if (inputStream == null) { + throw new IllegalStateException("missing SDK version resource " + VERSION_RESOURCE); + } var properties = new Properties(); properties.load(inputStream); - return properties.getProperty("version"); + var version = properties.getProperty("version"); + if (version == null || version.isBlank()) { + throw new IllegalStateException( + "SDK version resource " + VERSION_RESOURCE + " has no version"); + } + return version; } catch (IOException ex) { throw new IllegalStateException(ex); } diff --git a/src/test/java/io/getstream/services/framework/SdkVersionTest.java b/src/test/java/io/getstream/services/framework/SdkVersionTest.java new file mode 100644 index 00000000..b9c7f888 --- /dev/null +++ b/src/test/java/io/getstream/services/framework/SdkVersionTest.java @@ -0,0 +1,66 @@ +package io.getstream.services.framework; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import com.fasterxml.jackson.core.type.TypeReference; +import java.util.Map; +import java.util.Properties; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +// src/test/resources/version.properties is on the classpath ahead of the SDK jar and would be +// what ClassLoader.getResourceAsStream("version.properties") returned. The header must ignore it. +public class SdkVersionTest { + private MockWebServer server; + + @BeforeEach + void setUp() throws Exception { + server = new MockWebServer(); + server.start(); + } + + @AfterEach + void tearDown() throws Exception { + server.shutdown(); + } + + @Test + void clientHeaderUsesThisSdkVersionWhenAnotherVersionPropertiesIsFirst() throws Exception { + try (var decoy = + StreamHTTPClient.class.getClassLoader().getResourceAsStream("version.properties")) { + assertNotNull(decoy, "the test fixture version.properties is not on the classpath"); + var decoyProps = new Properties(); + decoyProps.load(decoy); + assertEquals("0.0.0-collision", decoyProps.getProperty("version")); + } + + String expected; + try (var own = + StreamHTTPClient.class.getResourceAsStream( + "/io/getstream/stream-sdk-java/version.properties")) { + assertNotNull(own); + var ownProps = new Properties(); + ownProps.load(own); + expected = "stream-java-client-" + ownProps.getProperty("version"); + } + + server.enqueue(new MockResponse().setResponseCode(200).setBody("{}")); + var client = new StreamHTTPClient("key", "012345678901234567890123456789ab"); + new StreamRequest>( + client.getHttpClient(), + client.getObjectMapper(), + server.url("/").toString(), + "GET", + "/api/v2/app", + null, + null, + new TypeReference<>() {}) + .execute(); + + assertEquals(expected, server.takeRequest().getHeader("X-Stream-Client")); + } +} diff --git a/src/test/resources/version.properties b/src/test/resources/version.properties new file mode 100644 index 00000000..3440ca8e --- /dev/null +++ b/src/test/resources/version.properties @@ -0,0 +1 @@ +version=0.0.0-collision