From ff8057b4355022c580478cd4f185ca407c70cfad Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 02:38:15 +0000 Subject: [PATCH 1/7] fix(client): r8 support --- .../META-INF/proguard/brand-dev-java-core.pro | 16 ++++---- brand-dev-java-proguard-test/build.gradle.kts | 40 ++++++++++++++++--- .../api/proguard/ProGuardCompatibilityTest.kt | 17 ++++++-- brand-dev-java-proguard-test/test.pro | 5 ++- 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro b/brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro index 595d923..0c2cf4e 100644 --- a/brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro +++ b/brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro @@ -1,5 +1,5 @@ # Jackson uses reflection and depends heavily on runtime attributes. --keepattributes +-keepattributes Exceptions,InnerClasses,Signature,Deprecated,*Annotation* # Jackson uses Kotlin reflection utilities, which themselves use reflection to access things. -keep class kotlin.reflect.** { *; } @@ -17,13 +17,13 @@ *; } -# Jackson uses reflection to access the default constructors of serializers and deserializers. --keepclassmembers class * extends com.branddev.api.core.BaseSerializer { - (); -} --keepclassmembers class * extends com.branddev.api.core.BaseDeserializer { - (); -} +# Jackson uses reified type information to serialize and deserialize our classes (via `TypeReference`). +-keep class com.fasterxml.jackson.core.type.TypeReference { *; } +-keep class * extends com.fasterxml.jackson.core.type.TypeReference { *; } + +# Jackson uses reflection to access our class serializers and deserializers. +-keep @com.fasterxml.jackson.databind.annotation.JsonSerialize class com.branddev.api.** { *; } +-keep @com.fasterxml.jackson.databind.annotation.JsonDeserialize class com.branddev.api.** { *; } # Jackson uses reflection to serialize and deserialize our classes based on their constructors and annotated members. -keepclassmembers class com.branddev.api.** { diff --git a/brand-dev-java-proguard-test/build.gradle.kts b/brand-dev-java-proguard-test/build.gradle.kts index 901fb98..ecf6c1e 100644 --- a/brand-dev-java-proguard-test/build.gradle.kts +++ b/brand-dev-java-proguard-test/build.gradle.kts @@ -4,8 +4,13 @@ plugins { } buildscript { + repositories { + google() + } + dependencies { classpath("com.guardsquare:proguard-gradle:7.4.2") + classpath("com.android.tools:r8:8.3.37") } } @@ -15,7 +20,6 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.assertj:assertj-core:3.25.3") testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") - testImplementation("org.junit.platform:junit-platform-console:1.10.1") } tasks.shadowJar { @@ -58,17 +62,43 @@ val testProGuard by tasks.registering(JavaExec::class) { dependsOn(proguardJar) notCompatibleWithConfigurationCache("ProGuard") - mainClass.set("org.junit.platform.console.ConsoleLauncher") + mainClass.set("com.branddev.api.proguard.ProGuardCompatibilityTest") classpath = files(proguardJarPath) +} + +val r8JarPath = "${layout.buildDirectory.get()}/libs/${project.name}-${project.version}-r8.jar" +val r8Jar by tasks.registering(JavaExec::class) { + group = "verification" + dependsOn(tasks.shadowJar) + notCompatibleWithConfigurationCache("R8") + + mainClass.set("com.android.tools.r8.R8") + classpath = buildscript.configurations["classpath"] + args = listOf( - "--classpath", proguardJarPath, - "--scan-classpath", - "--details", "verbose", + "--release", + "--classfile", + "--output", r8JarPath, + "--lib", System.getProperty("java.home"), + "--pg-conf", "./test.pro", + "--pg-conf", "../brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro", + "--pg-map-output", "${layout.buildDirectory.get()}/r8-mapping.txt", + tasks.shadowJar.get().archiveFile.get().asFile.absolutePath, ) } +val testR8 by tasks.registering(JavaExec::class) { + group = "verification" + dependsOn(r8Jar) + notCompatibleWithConfigurationCache("R8") + + mainClass.set("com.branddev.api.proguard.ProGuardCompatibilityTest") + classpath = files(r8JarPath) +} + tasks.test { dependsOn(testProGuard) + dependsOn(testR8) // We defer to the tests run via the ProGuard JAR. enabled = false } diff --git a/brand-dev-java-proguard-test/src/test/kotlin/com/branddev/api/proguard/ProGuardCompatibilityTest.kt b/brand-dev-java-proguard-test/src/test/kotlin/com/branddev/api/proguard/ProGuardCompatibilityTest.kt index 702b584..a3a24c3 100644 --- a/brand-dev-java-proguard-test/src/test/kotlin/com/branddev/api/proguard/ProGuardCompatibilityTest.kt +++ b/brand-dev-java-proguard-test/src/test/kotlin/com/branddev/api/proguard/ProGuardCompatibilityTest.kt @@ -6,20 +6,31 @@ import com.branddev.api.client.okhttp.BrandDevOkHttpClient import com.branddev.api.core.jsonMapper import com.branddev.api.models.brand.BrandRetrieveResponse import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import kotlin.reflect.full.memberFunctions +import kotlin.reflect.jvm.javaMethod import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test internal class ProGuardCompatibilityTest { companion object { - @BeforeAll @JvmStatic - fun setUp() { + fun main(args: Array) { // To debug that we're using the right JAR. val jarPath = this::class.java.getProtectionDomain().codeSource.location println("JAR being used: $jarPath") + + // We have to manually run the test methods instead of using the JUnit runner because it + // seems impossible to get working with R8. + val test = ProGuardCompatibilityTest() + test::class + .memberFunctions + .asSequence() + .filter { function -> + function.javaMethod?.isAnnotationPresent(Test::class.java) == true + } + .forEach { it.call(test) } } } diff --git a/brand-dev-java-proguard-test/test.pro b/brand-dev-java-proguard-test/test.pro index e9a70ba..316fd51 100644 --- a/brand-dev-java-proguard-test/test.pro +++ b/brand-dev-java-proguard-test/test.pro @@ -2,4 +2,7 @@ -keep class com.branddev.api.proguard.** { *; } # For the testing framework. --keep class org.junit.** { *; } \ No newline at end of file +-keep class org.junit.** { *; } + +# Many warnings don't apply for our testing purposes. +-dontwarn \ No newline at end of file From fd9496e8f38dd306d9afe5d46505b9122ffa81d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 02:44:13 +0000 Subject: [PATCH 2/7] chore(internal): reduce proguard ci logging --- brand-dev-java-proguard-test/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/brand-dev-java-proguard-test/build.gradle.kts b/brand-dev-java-proguard-test/build.gradle.kts index ecf6c1e..25bc9a4 100644 --- a/brand-dev-java-proguard-test/build.gradle.kts +++ b/brand-dev-java-proguard-test/build.gradle.kts @@ -37,7 +37,6 @@ val proguardJar by tasks.registering(proguard.gradle.ProGuardTask::class) { outjars(proguardJarPath) printmapping("${layout.buildDirectory.get()}/proguard-mapping.txt") - verbose() dontwarn() val javaHome = System.getProperty("java.home") From 27f86a9501ea5d2d3064c7cf3e9452c0a82701eb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 02:46:05 +0000 Subject: [PATCH 3/7] chore(internal): bump ci test timeout --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c152c54..cc7489a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ on: jobs: lint: - timeout-minutes: 10 + timeout-minutes: 15 name: lint runs-on: ${{ github.repository == 'stainless-sdks/brand.dev-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork @@ -37,7 +37,7 @@ jobs: - name: Run lints run: ./scripts/lint test: - timeout-minutes: 10 + timeout-minutes: 15 name: test runs-on: ${{ github.repository == 'stainless-sdks/brand.dev-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork From a01460d187cb30ba74603da061b98f769ad1e385 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 03:30:48 +0000 Subject: [PATCH 4/7] chore(internal): add async lock helper --- .../kotlin/com/branddev/api/core/Utils.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Utils.kt b/brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Utils.kt index 3fdb53d..c91cc5b 100644 --- a/brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Utils.kt +++ b/brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Utils.kt @@ -5,6 +5,8 @@ package com.branddev.api.core import com.branddev.api.errors.BrandDevInvalidDataException import java.util.Collections import java.util.SortedMap +import java.util.concurrent.CompletableFuture +import java.util.concurrent.locks.Lock @JvmSynthetic internal fun T?.getOrThrow(name: String): T = @@ -90,3 +92,24 @@ internal fun Any?.contentToString(): String { } internal interface Enum + +/** + * Executes the given [action] while holding the lock, returning a [CompletableFuture] with the + * result. + * + * @param action The asynchronous action to execute while holding the lock + * @return A [CompletableFuture] that completes with the result of the action + */ +@JvmSynthetic +internal fun Lock.withLockAsync(action: () -> CompletableFuture): CompletableFuture { + lock() + val future = + try { + action() + } catch (e: Throwable) { + unlock() + throw e + } + future.whenComplete { _, _ -> unlock() } + return future +} From 85af0f84d86739f9dc477078df30c6f574fc5c41 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 03:41:08 +0000 Subject: [PATCH 5/7] chore(example): fix run example comment --- brand-dev-java-example/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brand-dev-java-example/build.gradle.kts b/brand-dev-java-example/build.gradle.kts index 2ffc061..7011f42 100644 --- a/brand-dev-java-example/build.gradle.kts +++ b/brand-dev-java-example/build.gradle.kts @@ -18,7 +18,7 @@ tasks.withType().configureEach { application { // Use `./gradlew :brand-dev-java-example:run` to run `Main` - // Use `./gradlew :brand-dev-java-example:run -Dexample=Something` to run `SomethingExample` + // Use `./gradlew :brand-dev-java-example:run -Pexample=Something` to run `SomethingExample` mainClass = "com.branddev.api.example.${ if (project.hasProperty("example")) "${project.property("example")}Example" From 8b2f3419961aa90dc92cc9c4f51bae9413613434 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 02:18:04 +0000 Subject: [PATCH 6/7] chore: increase max gradle JVM heap to 8GB --- gradle.properties | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index ff76593..6680f9c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,12 +4,13 @@ org.gradle.parallel=true org.gradle.daemon=false # These options improve our compilation and test performance. They are inherited by the Kotlin daemon. org.gradle.jvmargs=\ - -Xms1g \ - -Xmx4g \ + -Xms2g \ + -Xmx8g \ -XX:+UseParallelGC \ -XX:InitialCodeCacheSize=256m \ -XX:ReservedCodeCacheSize=1G \ - -XX:MetaspaceSize=256m \ + -XX:MetaspaceSize=512m \ + -XX:MaxMetaspaceSize=2G \ -XX:TieredStopAtLevel=1 \ -XX:GCTimeRatio=4 \ -XX:CICompilerCount=4 \ From 6677ff143a77bd36d47449ff025c5cdc7ee05de5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 02:18:20 +0000 Subject: [PATCH 7/7] release: 0.1.0-alpha.9 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 17 +++++++++++++++++ README.md | 10 +++++----- build.gradle.kts | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c373724..46b9b6b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.8" + ".": "0.1.0-alpha.9" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 45e6619..f609c47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 0.1.0-alpha.9 (2025-08-08) + +Full Changelog: [v0.1.0-alpha.8...v0.1.0-alpha.9](https://github.com/brand-dot-dev/java-sdk/compare/v0.1.0-alpha.8...v0.1.0-alpha.9) + +### Bug Fixes + +* **client:** r8 support ([ff8057b](https://github.com/brand-dot-dev/java-sdk/commit/ff8057b4355022c580478cd4f185ca407c70cfad)) + + +### Chores + +* **example:** fix run example comment ([85af0f8](https://github.com/brand-dot-dev/java-sdk/commit/85af0f84d86739f9dc477078df30c6f574fc5c41)) +* increase max gradle JVM heap to 8GB ([8b2f341](https://github.com/brand-dot-dev/java-sdk/commit/8b2f3419961aa90dc92cc9c4f51bae9413613434)) +* **internal:** add async lock helper ([a01460d](https://github.com/brand-dot-dev/java-sdk/commit/a01460d187cb30ba74603da061b98f769ad1e385)) +* **internal:** bump ci test timeout ([27f86a9](https://github.com/brand-dot-dev/java-sdk/commit/27f86a9501ea5d2d3064c7cf3e9452c0a82701eb)) +* **internal:** reduce proguard ci logging ([fd9496e](https://github.com/brand-dot-dev/java-sdk/commit/fd9496e8f38dd306d9afe5d46505b9122ffa81d5)) + ## 0.1.0-alpha.8 (2025-07-23) Full Changelog: [v0.1.0-alpha.7...v0.1.0-alpha.8](https://github.com/brand-dot-dev/java-sdk/compare/v0.1.0-alpha.7...v0.1.0-alpha.8) diff --git a/README.md b/README.md index 5630a60..7ba837b 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.1.0-alpha.8) -[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.1.0-alpha.8/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.1.0-alpha.8) +[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.1.0-alpha.9) +[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.1.0-alpha.9/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.1.0-alpha.9) @@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/). -Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.1.0-alpha.8). +Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.1.0-alpha.9). @@ -24,7 +24,7 @@ Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/b ### Gradle ```kotlin -implementation("com.branddev.api:brand-dev-java:0.1.0-alpha.8") +implementation("com.branddev.api:brand-dev-java:0.1.0-alpha.9") ``` ### Maven @@ -33,7 +33,7 @@ implementation("com.branddev.api:brand-dev-java:0.1.0-alpha.8") com.branddev.api brand-dev-java - 0.1.0-alpha.8 + 0.1.0-alpha.9 ``` diff --git a/build.gradle.kts b/build.gradle.kts index cd3e3f6..76805bb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.branddev.api" - version = "0.1.0-alpha.8" // x-release-please-version + version = "0.1.0-alpha.9" // x-release-please-version } subprojects {