From 1123487233c3a781d70764bf38905a94c6c1e3dd Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 12:23:32 +0000 Subject: [PATCH 1/5] feat: sync Java client with Apify OpenAPI spec v2-2026-10-20T121847Z Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01UUMWnU4gH573HweHieMhHi --- CHANGELOG.md | 15 ++++++++ README.md | 8 ++-- docs/README.md | 2 +- docs/builds.md | 5 ++- docs/misc.md | 3 +- docs/runs.md | 7 ++-- pom.xml | 2 +- spotbugs-exclude.xml | 6 ++- src/main/java/com/apify/client/Version.java | 4 +- .../java/com/apify/client/build/Build.java | 10 +++++ .../apify/client/build/BuildActVersion.java | 38 +++++++++++++++++++ .../apify/client/run/RunChargeOptions.java | 15 ++++++++ .../java/com/apify/client/run/RunClient.java | 4 ++ .../com/apify/client/store/PricingInfo.java | 2 +- .../apify/client/store/StoreListOptions.java | 5 ++- .../client/ClientBehaviourRegressionTest.java | 14 +++++++ .../client/NestedDtoForwardCompatTest.java | 20 ++++++++++ 17 files changed, 141 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/apify/client/build/BuildActVersion.java diff --git a/CHANGELOG.md b/CHANGELOG.md index c642d4c..856d3f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to the Apify Java client are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.10.0] - 2026-10-21 + +### Added + +- `RunChargeOptions.requestId(String)`, sent as `requestId` in the charge request body: the ID of the + Server Actor request being charged, required for multi-tenant Server Actor runs. +- `Build.getActVersion()` and the `BuildActVersion` model; `buildTag` is `null` for a version without + a build tag. + +### Changed + +- Updated to Apify OpenAPI specification `v2-2026-10-20T121847Z`. +- Documented that the `FLAT_PRICE_PER_MONTH` (rental) pricing model is no longer supported and is no + longer accepted by the Store `pricingModel` filter. + ## [0.9.0] - 2026-10-19 ### Added diff --git a/README.md b/README.md index 980125c..c272636 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Maven (Maven Central is a default repository, so no extra configuration is neede com.apify apify-client - 0.9.0 + 0.10.0 ``` @@ -35,7 +35,7 @@ repositories { } dependencies { - implementation 'com.apify:apify-client:0.9.0' + implementation 'com.apify:apify-client:0.10.0' } ``` @@ -317,10 +317,10 @@ try { The public `com.apify.client.Version` class (`import com.apify.client.Version;`) exposes two constants: -- `Version.CLIENT_VERSION` — the semantic version of this client (`0.9.0`). +- `Version.CLIENT_VERSION` — the semantic version of this client (`0.10.0`). - `Version.API_SPEC_VERSION` — the version of the [Apify OpenAPI specification](https://docs.apify.com/api/openapi.json) (its `info.version` field) that this client's endpoints, parameters and models were last generated - and checked against (`v2-2026-10-08T073338Z`). It is a snapshot, not a live compatibility + and checked against (`v2-2026-10-20T121847Z`). It is a snapshot, not a live compatibility guarantee: the client keeps working against newer, backward-compatible spec revisions, but a feature added to the API after this snapshot has no corresponding method here yet. diff --git a/docs/README.md b/docs/README.md index e21c877..e5d7a39 100644 --- a/docs/README.md +++ b/docs/README.md @@ -41,7 +41,7 @@ option types, so import each resource you use from its own package: | `com.apify.client` (root) | `ApifyClient`, `ApifyClientBuilder`, `Version`, `PaginationList`, `ListOptions`, `StorageListOptions`, `ApifyResource` | | `com.apify.client.http` | `ApifyClientException`, `ApifyApiException`, `ApifyTransportException`, `HttpTransport`, `DefaultHttpTransport`, `HttpTimeoutException` | | `com.apify.client.actor` | `Actor`, `ActorClient`, `ActorCollectionClient`, `ActorListOptions`, `ActorStartOptions`, `ActorCallOptions`, `ActorBuildOptions`, `ActorStandby`, `ActorVersion`, `ActorVersionClient`, `ActorVersionCollectionClient`, `ActorEnvVar`, `ActorEnvVarClient`, `ActorEnvVarCollectionClient`, `ValidateInputOptions`, `ActorStats`, `ActorDefaultRunOptions` | -| `com.apify.client.build` | `Build`, `BuildClient`, `BuildCollectionClient`, `BuildMeta`, `BuildStats`, `BuildOptions`, `BuildUsage` | +| `com.apify.client.build` | `Build`, `BuildClient`, `BuildCollectionClient`, `BuildActVersion`, `BuildMeta`, `BuildStats`, `BuildOptions`, `BuildUsage` | | `com.apify.client.run` | `ActorRun`, `ActorRunStats`, `ActorRunOptions`, `ActorRunMeta`, `ActorRunUsage`, `RunClient`, `RunCollectionClient`, `RunListOptions`, `LastRunOptions`, `MetamorphOptions`, `RunChargeOptions`, `RunResurrectOptions`, `SetStatusMessageOptions` | | `com.apify.client.dataset` | `Dataset`, `DatasetClient`, `DatasetCollectionClient`, `DatasetListItemsOptions`, `DatasetDownloadOptions`, `DownloadItemsFormat` | | `com.apify.client.keyvalue` | `KeyValueStore`, `KeyValueStoreClient`, `KeyValueStoreCollectionClient`, `KeyValueStoreRecord`, `KeyValueStoreKeysPage`, `KeyValueStoreKey`, `GetRecordOptions`, `SetRecordOptions`, `ListKeysOptions` | diff --git a/docs/builds.md b/docs/builds.md index b5704a4..7f56329 100644 --- a/docs/builds.md +++ b/docs/builds.md @@ -23,7 +23,8 @@ builds) and a single build with `client.build(id)`. | `log()` | A `LogClient` for the build's log. | `Build` fields: `getId()`, `getActId()`, `getUserId()`, `getStatus()`, `getStartedAt()`, -`getFinishedAt()`, `getBuildNumber()`, `getImageDigest()` (`String`, nullable — the built Docker +`getFinishedAt()`, `getBuildNumber()`, `getActVersion()` (`BuildActVersion` — `getSourceType()`, `getBuildTag()` +(nullable), `getVersionNumber()`, `getGitRepoUrl()`), `getImageDigest()` (`String`, nullable — the built Docker image manifest's digest, without the `sha256:` prefix; compare two builds' digests to tell whether their image contents differ), `getMeta()` (`BuildMeta` — `getOrigin()`, `getClientIp()`, `getUserAgent()`), `getStats()` (`BuildStats` — `getDurationMillis()`/`getRunTimeSecs()` as `Long`, @@ -32,7 +33,7 @@ their image contents differ), `getMeta()` (`BuildMeta` — `getOrigin()`, `getCl `getUsage()` / `getUsageUsd()` (`BuildUsage` — `getActorComputeUnits()` as `Double`, the latter as its USD cost), `getUsageTotalUsd()` (`Double`), plus `isTerminal()` and `getExtra()`. The status is one of `READY`, `RUNNING`, `SUCCEEDED`, `FAILED`, `TIMING-OUT`, `TIMED-OUT`, `ABORTING`, `ABORTED`. -Every nested model above (`BuildMeta`, `BuildStats`, `BuildOptions`, `BuildUsage`) also has its own +Every nested model above (`BuildActVersion`, `BuildMeta`, `BuildStats`, `BuildOptions`, `BuildUsage`) also has its own `getExtra()`, so a field not yet listed here is still reachable rather than dropped. ```java diff --git a/docs/misc.md b/docs/misc.md index 2d86256..9043bba 100644 --- a/docs/misc.md +++ b/docs/misc.md @@ -12,7 +12,8 @@ Browse public Actors in the Apify Store. `client.store()` returns a `StoreCollec `StoreListOptions` fields: `offset` (number of Actors to skip), `limit` (maximum number of Actors to return), `search` (full-text search query), `sortBy` (the sort field, e.g. `popularity`, `newest`), `category` (filter Actors by category), `username` (filter Actors by owner username), `pricingModel` -(filter by pricing model: `FREE`, `FLAT_PRICE_PER_MONTH`, `PRICE_PER_DATASET_ITEM`, `PAY_PER_EVENT`), +(filter by pricing model: `FREE`, `PRICE_PER_DATASET_ITEM`, `PAY_PER_EVENT`; the rental model `FLAT_PRICE_PER_MONTH` is no +longer supported), `includeUnrunnableActors` (include Actors the current user cannot run), `allowsAgenticUsers` (only Actors that allow agentic users), `responseFormat` (the response shape: `full` or `agent`). diff --git a/docs/runs.md b/docs/runs.md index f406ddf..2668b71 100644 --- a/docs/runs.md +++ b/docs/runs.md @@ -151,9 +151,10 @@ nullable), `getMemoryMbytes()` (`Long`, nullable), `getDiskMbytes()` (`Long`, nu `getMaxItems()` (`Long`, nullable), `getMaxTotalChargeUsd()` (`Double`, nullable), `getRestartOnError()` (`Boolean`, nullable). -`RunChargeOptions` (constructed with the required event name) uses plain values: `count(Long)` and -`idempotencyKey(String)` — the latter is auto-generated when unset so a transport-retried charge is -applied at most once. +`RunChargeOptions` (constructed with the required event name) uses plain values: `count(Long)`, +`idempotencyKey(String)` — auto-generated when unset so a transport-retried charge is applied at +most once — and `requestId(String)`, the `X-Actor-Request-ID` of the Server Actor request being +charged (required for multi-tenant Server Actor runs, omitted otherwise). ```java client.run("RUN_ID").charge(new RunChargeOptions("my-event").count(3L)).join(); diff --git a/pom.xml b/pom.xml index d6753b4..e189322 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.apify apify-client - 0.9.0 + 0.10.0 jar Apify Java Client diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml index 4111b75..a3592e0 100644 --- a/spotbugs-exclude.xml +++ b/spotbugs-exclude.xml @@ -18,8 +18,8 @@ 2. UWF_UNWRITTEN_FIELD / UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD on Jackson-populated DTOs/response shapes ({@code KeyValueStoreKey}, {@code DeletedRequestInfo}, {@code ActorRunMeta}, {@code - TaskOptions}, {@code WebhookLastDispatch}, {@code ActorDefaultRunOptions}, {@code BuildMeta}, - {@code BuildOptions}, {@code BuildStats}, {@code PricingInfo}, {@code ProxyGroup}, {@code + TaskOptions}, {@code WebhookLastDispatch}, {@code ActorDefaultRunOptions}, {@code BuildActVersion}, + {@code BuildMeta}, {@code BuildOptions}, {@code BuildStats}, {@code PricingInfo}, {@code ProxyGroup}, {@code UserProxy}, {@code WebhookDispatchEventData}, {@code WebhookDispatchWebhookInfo}, the internal error-response mapping in {@code HttpClientCore}): their fields are written by the deserializer via reflection, which SpotBugs cannot see - a known false positive for @@ -74,6 +74,7 @@ + @@ -111,6 +112,7 @@ + diff --git a/src/main/java/com/apify/client/Version.java b/src/main/java/com/apify/client/Version.java index fe488ad..95b44ba 100644 --- a/src/main/java/com/apify/client/Version.java +++ b/src/main/java/com/apify/client/Version.java @@ -13,13 +13,13 @@ public final class Version { * The semantic version of this client library (see SemVer). * Changes to the public interface other than additive ones are considered breaking changes. */ - public static final String CLIENT_VERSION = "0.9.0"; + public static final String CLIENT_VERSION = "0.10.0"; /** * The version of the Apify OpenAPI specification this client was generated and verified against. * Corresponds to the {@code info.version} field of the Apify OpenAPI document. */ - public static final String API_SPEC_VERSION = "v2-2026-10-08T073338Z"; + public static final String API_SPEC_VERSION = "v2-2026-10-20T121847Z"; private Version() {} } diff --git a/src/main/java/com/apify/client/build/Build.java b/src/main/java/com/apify/client/build/Build.java index cd12040..185417b 100644 --- a/src/main/java/com/apify/client/build/Build.java +++ b/src/main/java/com/apify/client/build/Build.java @@ -14,6 +14,7 @@ public final class Build extends ApifyResource { private Instant finishedAt; private String buildNumber; private String imageDigest; + private BuildActVersion actVersion; private BuildMeta meta; private BuildStats stats; private BuildOptions options; @@ -69,6 +70,15 @@ public String getImageDigest() { return imageDigest; } + /** + * A snapshot of the Actor version this build was created from. Its {@link + * BuildActVersion#getBuildTag()} is {@code null} for a version without a build tag. Inline source + * files, when present, stay reachable through {@link BuildActVersion#getExtra()}. + */ + public BuildActVersion getActVersion() { + return actVersion; + } + /** Metadata about how the build was initiated. */ public BuildMeta getMeta() { return meta; diff --git a/src/main/java/com/apify/client/build/BuildActVersion.java b/src/main/java/com/apify/client/build/BuildActVersion.java new file mode 100644 index 0000000..732b69b --- /dev/null +++ b/src/main/java/com/apify/client/build/BuildActVersion.java @@ -0,0 +1,38 @@ +package com.apify.client.build; + +import com.apify.client.ApifyResource; + +/** A snapshot of the Actor version a {@link Build} was created from. */ +public final class BuildActVersion extends ApifyResource { + private String sourceType; + private String buildTag; + private String versionNumber; + private String gitRepoUrl; + + /** + * How the version's source was provided (e.g. {@code "SOURCE_FILES"}, {@code "GIT_REPO"}, {@code + * "TARBALL"}, {@code "GITHUB_GIST"}, {@code "SOURCE_CODE"}). + */ + public String getSourceType() { + return sourceType; + } + + /** + * The build tag of the Actor version the build was created from. {@code null} when the version + * has no build tag, in which case the build is tagged on success only if a tag was passed when + * starting it. + */ + public String getBuildTag() { + return buildTag; + } + + /** The version number (e.g. {@code "0.1"}). */ + public String getVersionNumber() { + return versionNumber; + } + + /** URL of the Git repository; present when the source type is {@code GIT_REPO}. */ + public String getGitRepoUrl() { + return gitRepoUrl; + } +} diff --git a/src/main/java/com/apify/client/run/RunChargeOptions.java b/src/main/java/com/apify/client/run/RunChargeOptions.java index 7a3f64a..6c19fc9 100644 --- a/src/main/java/com/apify/client/run/RunChargeOptions.java +++ b/src/main/java/com/apify/client/run/RunChargeOptions.java @@ -5,6 +5,7 @@ public final class RunChargeOptions { private String eventName; private Long count; private String idempotencyKey; + private String requestId; /** Creates options for the given (required) event name. */ public RunChargeOptions(String eventName) { @@ -32,6 +33,16 @@ public RunChargeOptions idempotencyKey(String idempotencyKey) { return this; } + /** + * The ID of the Server Actor request being charged, taken from the {@code X-Actor-Request-ID} + * header of the incoming request. Required for multi-tenant Server Actor runs, where it + * identifies the request the charge belongs to; omit it otherwise. + */ + public RunChargeOptions requestId(String requestId) { + this.requestId = requestId; + return this; + } + String eventNameValue() { return eventName; } @@ -43,4 +54,8 @@ long countValue() { String idempotencyKeyValue() { return idempotencyKey; } + + String requestIdValue() { + return requestId; + } } diff --git a/src/main/java/com/apify/client/run/RunClient.java b/src/main/java/com/apify/client/run/RunClient.java index a8dd46b..3bf64a5 100644 --- a/src/main/java/com/apify/client/run/RunClient.java +++ b/src/main/java/com/apify/client/run/RunClient.java @@ -172,6 +172,10 @@ public CompletableFuture charge(RunChargeOptions options) { Map body = new LinkedHashMap<>(); body.put("eventName", eventName); body.put("count", options.countValue()); + String requestId = options.requestIdValue(); + if (requestId != null && !requestId.isEmpty()) { + body.put("requestId", requestId); + } Map headers = Map.of(CHARGE_IDEMPOTENCY_HEADER, idempotencyKey); // Route through mergedParams like the run's other actions, so a last-run-seeded context charges // the same run its read methods resolve to (its pinned status/origin filters are preserved). diff --git a/src/main/java/com/apify/client/store/PricingInfo.java b/src/main/java/com/apify/client/store/PricingInfo.java index 6710933..3d7c728 100644 --- a/src/main/java/com/apify/client/store/PricingInfo.java +++ b/src/main/java/com/apify/client/store/PricingInfo.java @@ -7,7 +7,7 @@ public final class PricingInfo extends ApifyResource { private String pricingModel; /** - * The pricing model, e.g. {@code "FREE"}, {@code "FLAT_PRICE_PER_MONTH"}, {@code + * The pricing model, e.g. {@code "FREE"}, {@code "PRICE_PER_DATASET_ITEM"}, {@code * "PAY_PER_EVENT"}. */ public String getPricingModel() { diff --git a/src/main/java/com/apify/client/store/StoreListOptions.java b/src/main/java/com/apify/client/store/StoreListOptions.java index 785415a..40fe374 100644 --- a/src/main/java/com/apify/client/store/StoreListOptions.java +++ b/src/main/java/com/apify/client/store/StoreListOptions.java @@ -56,8 +56,9 @@ public StoreListOptions username(String username) { } /** - * Filter Actors by pricing model ({@code FREE}, {@code FLAT_PRICE_PER_MONTH}, {@code - * PRICE_PER_DATASET_ITEM}, {@code PAY_PER_EVENT}). + * Filter Actors by pricing model ({@code FREE}, {@code PRICE_PER_DATASET_ITEM}, {@code + * PAY_PER_EVENT}). The rental model ({@code FLAT_PRICE_PER_MONTH}) is no longer supported and is + * not accepted as a filter. */ public StoreListOptions pricingModel(String pricingModel) { this.pricingModel = pricingModel; diff --git a/src/test/java/com/apify/client/ClientBehaviourRegressionTest.java b/src/test/java/com/apify/client/ClientBehaviourRegressionTest.java index 7d19607..62b5771 100644 --- a/src/test/java/com/apify/client/ClientBehaviourRegressionTest.java +++ b/src/test/java/com/apify/client/ClientBehaviourRegressionTest.java @@ -119,6 +119,20 @@ void chargeHonorsExplicitIdempotencyKey() { assertEquals("fixed-key", backend.lastHeaders.firstValue("idempotency-key").orElse("")); } + @Test + void chargeSendsRequestIdOnlyWhenSet() { + MockTransport withId = MockTransport.ofConstant(200, "{\"data\":{}}"); + client(withId) + .run("run123") + .charge(new RunChargeOptions("e").requestId("7Hs2kQw9LxP4mN1vB")) + .join(); + assertTrue(withId.lastBody.contains("\"requestId\":\"7Hs2kQw9LxP4mN1vB\""), withId.lastBody); + + MockTransport without = MockTransport.ofConstant(200, "{\"data\":{}}"); + client(without).run("run123").charge(new RunChargeOptions("e")).join(); + assertFalse(without.lastBody.contains("requestId"), without.lastBody); + } + @Test void chargeRejectsMissingEventName() { MockTransport backend = MockTransport.ofConstant(200, "{\"data\":{}}"); diff --git a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java index 4e5167a..f76fb8a 100644 --- a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java +++ b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.apify.client.actor.ActorStandby; +import com.apify.client.build.Build; import com.apify.client.build.BuildStats; import com.apify.client.internal.Json; import com.apify.client.keyvalue.KeyValueStoreKeysPage; @@ -73,6 +74,25 @@ void buildStatsModelsImageSizeBytesAndKeepsUnknownFields() { assertEquals(true, stats.getExtra().get("someFutureStatField")); } + @Test + void buildActVersionAcceptsNullBuildTag() { + Build tagged = + parse( + "{\"id\":\"b1\",\"actVersion\":{\"sourceType\":\"GIT_REPO\"," + + "\"buildTag\":\"latest\",\"versionNumber\":\"0.1\"}}", + Build.class); + assertEquals("latest", tagged.getActVersion().getBuildTag()); + assertEquals("0.1", tagged.getActVersion().getVersionNumber()); + + Build untagged = + parse( + "{\"id\":\"b2\",\"actVersion\":{\"sourceType\":\"SOURCE_FILES\"," + + "\"buildTag\":null,\"versionNumber\":\"0.0\"}}", + Build.class); + assertEquals(null, untagged.getActVersion().getBuildTag()); + assertEquals("SOURCE_FILES", untagged.getActVersion().getSourceType()); + } + /** * Every other nested value DTO in the audit (one representative per resource package) also * preserves fields it has no typed getter for, instead of discarding them — the general fix, not From 20f3c2da91fa59d749306ef0b341f1d5342c4f8f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 12:32:00 +0000 Subject: [PATCH 2/5] fix: address review - SourceCodeFile/sourceFiles on BuildActVersion, correct pricing filter wording, extend tests Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01UUMWnU4gH573HweHieMhHi --- CHANGELOG.md | 8 +++--- docs/README.md | 2 +- docs/builds.md | 3 +- docs/misc.md | 4 +-- spotbugs-exclude.xml | 1 + .../apify/client/actor/SourceCodeFile.java | 28 +++++++++++++++++++ .../java/com/apify/client/build/Build.java | 3 +- .../apify/client/build/BuildActVersion.java | 9 ++++++ .../apify/client/store/StoreListOptions.java | 4 +-- .../client/NestedDtoForwardCompatTest.java | 15 ++++++++-- 10 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/apify/client/actor/SourceCodeFile.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 856d3f1..dfb9f00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,14 +11,14 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - `RunChargeOptions.requestId(String)`, sent as `requestId` in the charge request body: the ID of the Server Actor request being charged, required for multi-tenant Server Actor runs. -- `Build.getActVersion()` and the `BuildActVersion` model; `buildTag` is `null` for a version without - a build tag. +- `Build.getActVersion()` and the `BuildActVersion` model (with the `SourceCodeFile` model for its + inline `sourceFiles`); `buildTag` is `null` for a version without a build tag. ### Changed - Updated to Apify OpenAPI specification `v2-2026-10-20T121847Z`. -- Documented that the `FLAT_PRICE_PER_MONTH` (rental) pricing model is no longer supported and is no - longer accepted by the Store `pricingModel` filter. +- Documented that the `FLAT_PRICE_PER_MONTH` (rental) pricing model is deprecated and no longer + listed as a Store `pricingModel` filter value. ## [0.9.0] - 2026-10-19 diff --git a/docs/README.md b/docs/README.md index e5d7a39..04ad78f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -40,7 +40,7 @@ option types, so import each resource you use from its own package: |---|---| | `com.apify.client` (root) | `ApifyClient`, `ApifyClientBuilder`, `Version`, `PaginationList`, `ListOptions`, `StorageListOptions`, `ApifyResource` | | `com.apify.client.http` | `ApifyClientException`, `ApifyApiException`, `ApifyTransportException`, `HttpTransport`, `DefaultHttpTransport`, `HttpTimeoutException` | -| `com.apify.client.actor` | `Actor`, `ActorClient`, `ActorCollectionClient`, `ActorListOptions`, `ActorStartOptions`, `ActorCallOptions`, `ActorBuildOptions`, `ActorStandby`, `ActorVersion`, `ActorVersionClient`, `ActorVersionCollectionClient`, `ActorEnvVar`, `ActorEnvVarClient`, `ActorEnvVarCollectionClient`, `ValidateInputOptions`, `ActorStats`, `ActorDefaultRunOptions` | +| `com.apify.client.actor` | `Actor`, `ActorClient`, `ActorCollectionClient`, `ActorListOptions`, `ActorStartOptions`, `ActorCallOptions`, `ActorBuildOptions`, `ActorStandby`, `ActorVersion`, `SourceCodeFile`, `ActorVersionClient`, `ActorVersionCollectionClient`, `ActorEnvVar`, `ActorEnvVarClient`, `ActorEnvVarCollectionClient`, `ValidateInputOptions`, `ActorStats`, `ActorDefaultRunOptions` | | `com.apify.client.build` | `Build`, `BuildClient`, `BuildCollectionClient`, `BuildActVersion`, `BuildMeta`, `BuildStats`, `BuildOptions`, `BuildUsage` | | `com.apify.client.run` | `ActorRun`, `ActorRunStats`, `ActorRunOptions`, `ActorRunMeta`, `ActorRunUsage`, `RunClient`, `RunCollectionClient`, `RunListOptions`, `LastRunOptions`, `MetamorphOptions`, `RunChargeOptions`, `RunResurrectOptions`, `SetStatusMessageOptions` | | `com.apify.client.dataset` | `Dataset`, `DatasetClient`, `DatasetCollectionClient`, `DatasetListItemsOptions`, `DatasetDownloadOptions`, `DownloadItemsFormat` | diff --git a/docs/builds.md b/docs/builds.md index 7f56329..b1f5d8c 100644 --- a/docs/builds.md +++ b/docs/builds.md @@ -24,7 +24,8 @@ builds) and a single build with `client.build(id)`. `Build` fields: `getId()`, `getActId()`, `getUserId()`, `getStatus()`, `getStartedAt()`, `getFinishedAt()`, `getBuildNumber()`, `getActVersion()` (`BuildActVersion` — `getSourceType()`, `getBuildTag()` -(nullable), `getVersionNumber()`, `getGitRepoUrl()`), `getImageDigest()` (`String`, nullable — the built Docker +(nullable), `getVersionNumber()`, `getGitRepoUrl()`, `getSourceFiles()` (`List` — `getName()`, +`getFormat()`, `getContent()`)), `getImageDigest()` (`String`, nullable — the built Docker image manifest's digest, without the `sha256:` prefix; compare two builds' digests to tell whether their image contents differ), `getMeta()` (`BuildMeta` — `getOrigin()`, `getClientIp()`, `getUserAgent()`), `getStats()` (`BuildStats` — `getDurationMillis()`/`getRunTimeSecs()` as `Long`, diff --git a/docs/misc.md b/docs/misc.md index 9043bba..63b8773 100644 --- a/docs/misc.md +++ b/docs/misc.md @@ -12,8 +12,8 @@ Browse public Actors in the Apify Store. `client.store()` returns a `StoreCollec `StoreListOptions` fields: `offset` (number of Actors to skip), `limit` (maximum number of Actors to return), `search` (full-text search query), `sortBy` (the sort field, e.g. `popularity`, `newest`), `category` (filter Actors by category), `username` (filter Actors by owner username), `pricingModel` -(filter by pricing model: `FREE`, `PRICE_PER_DATASET_ITEM`, `PAY_PER_EVENT`; the rental model `FLAT_PRICE_PER_MONTH` is no -longer supported), +(filter by pricing model: `FREE`, `PRICE_PER_DATASET_ITEM`, `PAY_PER_EVENT`; the deprecated rental model +`FLAT_PRICE_PER_MONTH` is no longer listed), `includeUnrunnableActors` (include Actors the current user cannot run), `allowsAgenticUsers` (only Actors that allow agentic users), `responseFormat` (the response shape: `full` or `agent`). diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml index a3592e0..cfafadb 100644 --- a/spotbugs-exclude.xml +++ b/spotbugs-exclude.xml @@ -75,6 +75,7 @@ + diff --git a/src/main/java/com/apify/client/actor/SourceCodeFile.java b/src/main/java/com/apify/client/actor/SourceCodeFile.java new file mode 100644 index 0000000..8a1c98f --- /dev/null +++ b/src/main/java/com/apify/client/actor/SourceCodeFile.java @@ -0,0 +1,28 @@ +package com.apify.client.actor; + +import com.apify.client.ApifyResource; + +/** A single file in an Actor's source code. */ +public final class SourceCodeFile extends ApifyResource { + private String name; + private String format; + private String content; + + /** The path of the file relative to the Actor's root directory. */ + public String getName() { + return name; + } + + /** + * The format of {@link #getContent()}: {@code "TEXT"} for plain text, {@code "BASE64"} for + * encoded content. + */ + public String getFormat() { + return format; + } + + /** The contents of the file, interpreted according to {@link #getFormat()}. */ + public String getContent() { + return content; + } +} diff --git a/src/main/java/com/apify/client/build/Build.java b/src/main/java/com/apify/client/build/Build.java index 185417b..7a01932 100644 --- a/src/main/java/com/apify/client/build/Build.java +++ b/src/main/java/com/apify/client/build/Build.java @@ -72,8 +72,7 @@ public String getImageDigest() { /** * A snapshot of the Actor version this build was created from. Its {@link - * BuildActVersion#getBuildTag()} is {@code null} for a version without a build tag. Inline source - * files, when present, stay reachable through {@link BuildActVersion#getExtra()}. + * BuildActVersion#getBuildTag()} is {@code null} for a version without a build tag. */ public BuildActVersion getActVersion() { return actVersion; diff --git a/src/main/java/com/apify/client/build/BuildActVersion.java b/src/main/java/com/apify/client/build/BuildActVersion.java index 732b69b..74d7c1d 100644 --- a/src/main/java/com/apify/client/build/BuildActVersion.java +++ b/src/main/java/com/apify/client/build/BuildActVersion.java @@ -1,6 +1,9 @@ package com.apify.client.build; import com.apify.client.ApifyResource; +import com.apify.client.actor.SourceCodeFile; +import java.util.Collections; +import java.util.List; /** A snapshot of the Actor version a {@link Build} was created from. */ public final class BuildActVersion extends ApifyResource { @@ -8,6 +11,7 @@ public final class BuildActVersion extends ApifyResource { private String buildTag; private String versionNumber; private String gitRepoUrl; + private List sourceFiles; /** * How the version's source was provided (e.g. {@code "SOURCE_FILES"}, {@code "GIT_REPO"}, {@code @@ -35,4 +39,9 @@ public String getVersionNumber() { public String getGitRepoUrl() { return gitRepoUrl; } + + /** The inline source files; present when the source type is {@code SOURCE_FILES}. */ + public List getSourceFiles() { + return sourceFiles == null ? null : Collections.unmodifiableList(sourceFiles); + } } diff --git a/src/main/java/com/apify/client/store/StoreListOptions.java b/src/main/java/com/apify/client/store/StoreListOptions.java index 40fe374..df086b3 100644 --- a/src/main/java/com/apify/client/store/StoreListOptions.java +++ b/src/main/java/com/apify/client/store/StoreListOptions.java @@ -57,8 +57,8 @@ public StoreListOptions username(String username) { /** * Filter Actors by pricing model ({@code FREE}, {@code PRICE_PER_DATASET_ITEM}, {@code - * PAY_PER_EVENT}). The rental model ({@code FLAT_PRICE_PER_MONTH}) is no longer supported and is - * not accepted as a filter. + * PAY_PER_EVENT}). The rental model ({@code FLAT_PRICE_PER_MONTH}) is deprecated and no longer + * supported, so it is no longer documented as a filter value and matches no Actors. */ public StoreListOptions pricingModel(String pricingModel) { this.pricingModel = pricingModel; diff --git a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java index f76fb8a..ea3b5a9 100644 --- a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java +++ b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java @@ -1,6 +1,7 @@ package com.apify.client; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import com.apify.client.actor.ActorStandby; @@ -79,17 +80,25 @@ void buildActVersionAcceptsNullBuildTag() { Build tagged = parse( "{\"id\":\"b1\",\"actVersion\":{\"sourceType\":\"GIT_REPO\"," - + "\"buildTag\":\"latest\",\"versionNumber\":\"0.1\"}}", + + "\"buildTag\":\"latest\",\"versionNumber\":\"0.1\"," + + "\"gitRepoUrl\":\"https://github.com/apify/x.git\"}}", Build.class); assertEquals("latest", tagged.getActVersion().getBuildTag()); assertEquals("0.1", tagged.getActVersion().getVersionNumber()); + assertEquals("GIT_REPO", tagged.getActVersion().getSourceType()); + assertEquals("https://github.com/apify/x.git", tagged.getActVersion().getGitRepoUrl()); Build untagged = parse( "{\"id\":\"b2\",\"actVersion\":{\"sourceType\":\"SOURCE_FILES\"," - + "\"buildTag\":null,\"versionNumber\":\"0.0\"}}", + + "\"buildTag\":null,\"versionNumber\":\"0.0\",\"sourceFiles\":[" + + "{\"name\":\"main.js\",\"format\":\"TEXT\",\"content\":\"x\"}]}}", Build.class); - assertEquals(null, untagged.getActVersion().getBuildTag()); + assertNull(untagged.getActVersion().getBuildTag()); + assertEquals(1, untagged.getActVersion().getSourceFiles().size()); + assertEquals("main.js", untagged.getActVersion().getSourceFiles().get(0).getName()); + assertEquals("TEXT", untagged.getActVersion().getSourceFiles().get(0).getFormat()); + assertEquals("x", untagged.getActVersion().getSourceFiles().get(0).getContent()); assertEquals("SOURCE_FILES", untagged.getActVersion().getSourceType()); } From d70019aeec3e35b15da92be78994fbf88c02ed6c Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 12:44:52 +0000 Subject: [PATCH 3/5] fix: own-task webhook conditions in integration tests, empty list for absent sourceFiles Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01UUMWnU4gH573HweHieMhHi --- .../apify/client/build/BuildActVersion.java | 7 +- .../client/NestedDtoForwardCompatTest.java | 1 + .../integration/IterationIntegrationTest.java | 13 +- .../integration/WebhookIntegrationTest.java | 121 +++++++++++------- 4 files changed, 93 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/apify/client/build/BuildActVersion.java b/src/main/java/com/apify/client/build/BuildActVersion.java index 74d7c1d..2e66599 100644 --- a/src/main/java/com/apify/client/build/BuildActVersion.java +++ b/src/main/java/com/apify/client/build/BuildActVersion.java @@ -40,8 +40,11 @@ public String getGitRepoUrl() { return gitRepoUrl; } - /** The inline source files; present when the source type is {@code SOURCE_FILES}. */ + /** + * The inline source files; non-empty only when the source type is {@code SOURCE_FILES}, an empty + * list otherwise. + */ public List getSourceFiles() { - return sourceFiles == null ? null : Collections.unmodifiableList(sourceFiles); + return sourceFiles == null ? List.of() : Collections.unmodifiableList(sourceFiles); } } diff --git a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java index ea3b5a9..8b0baeb 100644 --- a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java +++ b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java @@ -87,6 +87,7 @@ void buildActVersionAcceptsNullBuildTag() { assertEquals("0.1", tagged.getActVersion().getVersionNumber()); assertEquals("GIT_REPO", tagged.getActVersion().getSourceType()); assertEquals("https://github.com/apify/x.git", tagged.getActVersion().getGitRepoUrl()); + assertTrue(tagged.getActVersion().getSourceFiles().isEmpty()); Build untagged = parse( diff --git a/src/test/java/com/apify/client/integration/IterationIntegrationTest.java b/src/test/java/com/apify/client/integration/IterationIntegrationTest.java index 1d472aa..2270130 100644 --- a/src/test/java/com/apify/client/integration/IterationIntegrationTest.java +++ b/src/test/java/com/apify/client/integration/IterationIntegrationTest.java @@ -300,12 +300,15 @@ void iterateSchedules() { void iterateWebhooks() { ApifyClient client = requireClient(); Set ids = new HashSet<>(); + Task task = WebhookIntegrationTest.createOwnedTask(client); try { for (int i = 0; i < 2; i++) { ids.add( client .webhooks() - .create(WebhookIntegrationTest.webhookDef("https://example.com/it-wh-" + i)) + .create( + WebhookIntegrationTest.webhookDef( + "https://example.com/it-wh-" + i, task.getId())) .join() .getId()); } @@ -315,8 +318,12 @@ void iterateWebhooks() { Webhook::getId, ids)); } finally { - for (String id : ids) { - client.webhook(id).delete().join(); + try { + for (String id : ids) { + client.webhook(id).delete().join(); + } + } finally { + client.task(task.getId()).delete().join(); } } } diff --git a/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java b/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java index a8ca400..b17bbb9 100644 --- a/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java +++ b/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java @@ -1,10 +1,12 @@ package com.apify.client.integration; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import com.apify.client.ApifyClient; import com.apify.client.ListOptions; +import com.apify.client.task.Task; import com.apify.client.webhook.Webhook; import com.apify.client.webhook.WebhookClient; import com.apify.client.webhook.WebhookDispatch; @@ -14,18 +16,29 @@ class WebhookIntegrationTest extends IntegrationBase { - static Map webhookDef(String url) { + /** + * A persistent (non-ad-hoc) webhook definition conditioned on the given task. The API rejects a + * condition that targets a resource that does not exist, and ad hoc webhooks can only target + * Actor runs. A webhook on a shared Actor would fire on other suites' concurrent runs, so each + * test conditions its webhook on a task it owns. + */ + static Map webhookDef(String url, String taskId) { return Map.of( "isAdHoc", - true, + false, "eventTypes", List.of("ACTOR.RUN.SUCCEEDED"), "condition", - Map.of("actorRunId", "ZZZZZZZZZZZZZZZZZ"), + Map.of("actorTaskId", taskId), "requestUrl", url); } + /** Creates a uniquely named task owned by the calling test; the caller deletes it. */ + static Task createOwnedTask(ApifyClient client) { + return client.tasks().create(TaskIntegrationTest.taskDef(uniqueName("wh-task"))).join(); + } + @Test void listWebhooks() { ApifyClient client = requireClient(); @@ -41,67 +54,87 @@ void listWebhookDispatches() { @Test void getWebhook() { ApifyClient client = requireClient(); - Webhook wh = client.webhooks().create(webhookDef("https://example.com/webhook")).join(); + Task task = createOwnedTask(client); try { - var got = client.webhook(wh.getId()).get().join(); - assertTrue(got.isPresent()); - assertEquals(wh.getId(), got.get().getId()); + Webhook wh = + client.webhooks().create(webhookDef("https://example.com/webhook", task.getId())).join(); + try { + var got = client.webhook(wh.getId()).get().join(); + assertTrue(got.isPresent()); + assertEquals(wh.getId(), got.get().getId()); + } finally { + client.webhook(wh.getId()).delete().join(); + } } finally { - client.webhook(wh.getId()).delete().join(); + client.task(task.getId()).delete().join(); } } @Test void getWebhookDispatch() { ApifyClient client = requireClient(); - Webhook wh = client.webhooks().create(webhookDef("https://example.com/webhook")).join(); + Task task = createOwnedTask(client); try { - WebhookDispatch dispatch = client.webhook(wh.getId()).test().join(); - var got = client.webhookDispatch(dispatch.getId()).get().join(); - assertTrue(got.isPresent()); - assertEquals(dispatch.getId(), got.get().getId()); + Webhook wh = + client.webhooks().create(webhookDef("https://example.com/webhook", task.getId())).join(); + try { + WebhookDispatch dispatch = client.webhook(wh.getId()).test().join(); + var got = client.webhookDispatch(dispatch.getId()).get().join(); + assertTrue(got.isPresent()); + assertEquals(dispatch.getId(), got.get().getId()); + } finally { + client.webhook(wh.getId()).delete().join(); + } } finally { - client.webhook(wh.getId()).delete().join(); + client.task(task.getId()).delete().join(); } } @Test void webhookCrudFlow() { ApifyClient client = requireClient(); - Webhook wh = client.webhooks().create(webhookDef("https://example.com/webhook")).join(); + Task task = createOwnedTask(client); try { - WebhookClient webhook = client.webhook(wh.getId()); - assertTrue(webhook.get().join().isPresent()); - Webhook updated = webhook.update(Map.of("requestUrl", "https://example.com/updated")).join(); - assertEquals("https://example.com/updated", updated.getRequestUrl()); - webhook.dispatches().list(new ListOptions()).join(); - webhook.test().join(); + Webhook wh = + client.webhooks().create(webhookDef("https://example.com/webhook", task.getId())).join(); + try { + WebhookClient webhook = client.webhook(wh.getId()); + assertTrue(webhook.get().join().isPresent()); + Webhook updated = + webhook.update(Map.of("requestUrl", "https://example.com/updated")).join(); + assertEquals("https://example.com/updated", updated.getRequestUrl()); + webhook.dispatches().list(new ListOptions()).join(); + webhook.test().join(); - // list() step of the create/get/modify/list/delete flow: verify the just-created webhook - // appears in the top-level collection listing. - boolean foundInList = - pollUntil( - LIST_FIND_ATTEMPTS, - LIST_FIND_BACKOFF_MILLIS, - () -> - client - .webhooks() - .list(new ListOptions().desc(true).limit(10L)) - .join() - .getItems() - .stream() - .anyMatch(w -> wh.getId().equals(w.getId()))); - assertTrue(foundInList, "expected the just-created webhook to appear in the top-level list"); + // list() step of the create/get/modify/list/delete flow: verify the just-created webhook + // appears in the top-level collection listing. + boolean foundInList = + pollUntil( + LIST_FIND_ATTEMPTS, + LIST_FIND_BACKOFF_MILLIS, + () -> + client + .webhooks() + .list(new ListOptions().desc(true).limit(10L)) + .join() + .getItems() + .stream() + .anyMatch(w -> wh.getId().equals(w.getId()))); + assertTrue( + foundInList, "expected the just-created webhook to appear in the top-level list"); - // Typed getters (previously only reachable via getExtra()): verify the API's response - // actually deserializes into them, not just that the code compiles. - assertTrue(wh.isAdHoc()); - assertTrue(wh.getCondition() != null); - assertTrue(wh.getCreatedAt() != null); - assertTrue(wh.getModifiedAt() != null); - assertTrue(wh.getStats() != null); + // Typed getters (previously only reachable via getExtra()): verify the API's response + // actually deserializes into them, not just that the code compiles. + assertFalse(wh.isAdHoc()); + assertTrue(wh.getCondition() != null); + assertTrue(wh.getCreatedAt() != null); + assertTrue(wh.getModifiedAt() != null); + assertTrue(wh.getStats() != null); + } finally { + client.webhook(wh.getId()).delete().join(); + } } finally { - client.webhook(wh.getId()).delete().join(); + client.task(task.getId()).delete().join(); } } } From e70151790904db7fc424d7ba3758b0dae1995179 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 12:51:39 +0000 Subject: [PATCH 4/5] test: assert webhook condition target and cover isAdHoc parsing offline Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01UUMWnU4gH573HweHieMhHi --- .../client/NestedDtoForwardCompatTest.java | 19 +++++++++++++++++++ .../integration/WebhookIntegrationTest.java | 4 +--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java index 8b0baeb..5f700f6 100644 --- a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java +++ b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java @@ -1,6 +1,7 @@ package com.apify.client; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -16,6 +17,7 @@ import com.apify.client.store.PricingInfo; import com.apify.client.task.TaskStats; import com.apify.client.user.UserProfile; +import com.apify.client.webhook.Webhook; import com.apify.client.webhook.WebhookStats; import java.nio.charset.StandardCharsets; import java.time.Instant; @@ -103,6 +105,23 @@ void buildActVersionAcceptsNullBuildTag() { assertEquals("SOURCE_FILES", untagged.getActVersion().getSourceType()); } + @Test + void webhookModelsAdHocFlagAndCondition() { + Webhook adHoc = + parse( + "{\"id\":\"w1\",\"isAdHoc\":true,\"condition\":{\"actorRunId\":\"run1\"}}", + Webhook.class); + assertTrue(adHoc.isAdHoc()); + assertEquals("run1", adHoc.getCondition().get("actorRunId").asText()); + + Webhook persistent = + parse( + "{\"id\":\"w2\",\"isAdHoc\":false,\"condition\":{\"actorTaskId\":\"t1\"}}", + Webhook.class); + assertFalse(persistent.isAdHoc()); + assertEquals("t1", persistent.getCondition().get("actorTaskId").asText()); + } + /** * Every other nested value DTO in the audit (one representative per resource package) also * preserves fields it has no typed getter for, instead of discarding them — the general fix, not diff --git a/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java b/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java index b17bbb9..3945a91 100644 --- a/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java +++ b/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java @@ -1,7 +1,6 @@ package com.apify.client.integration; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import com.apify.client.ApifyClient; @@ -125,8 +124,7 @@ void webhookCrudFlow() { // Typed getters (previously only reachable via getExtra()): verify the API's response // actually deserializes into them, not just that the code compiles. - assertFalse(wh.isAdHoc()); - assertTrue(wh.getCondition() != null); + assertEquals(task.getId(), wh.getCondition().get("actorTaskId").asText()); assertTrue(wh.getCreatedAt() != null); assertTrue(wh.getModifiedAt() != null); assertTrue(wh.getStats() != null); From 5c6637691b266b5885bfd65f22efbbf0fe4242c5 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 12:56:59 +0000 Subject: [PATCH 5/5] test: use non-deprecated JsonNode.asString and drop vacuous assertion Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01UUMWnU4gH573HweHieMhHi --- .../java/com/apify/client/NestedDtoForwardCompatTest.java | 6 ++---- .../apify/client/integration/WebhookIntegrationTest.java | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java index 5f700f6..64278e2 100644 --- a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java +++ b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java @@ -1,7 +1,6 @@ package com.apify.client; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -112,14 +111,13 @@ void webhookModelsAdHocFlagAndCondition() { "{\"id\":\"w1\",\"isAdHoc\":true,\"condition\":{\"actorRunId\":\"run1\"}}", Webhook.class); assertTrue(adHoc.isAdHoc()); - assertEquals("run1", adHoc.getCondition().get("actorRunId").asText()); + assertEquals("run1", adHoc.getCondition().get("actorRunId").asString()); Webhook persistent = parse( "{\"id\":\"w2\",\"isAdHoc\":false,\"condition\":{\"actorTaskId\":\"t1\"}}", Webhook.class); - assertFalse(persistent.isAdHoc()); - assertEquals("t1", persistent.getCondition().get("actorTaskId").asText()); + assertEquals("t1", persistent.getCondition().get("actorTaskId").asString()); } /** diff --git a/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java b/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java index 3945a91..f2b6b55 100644 --- a/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java +++ b/src/test/java/com/apify/client/integration/WebhookIntegrationTest.java @@ -124,7 +124,7 @@ void webhookCrudFlow() { // Typed getters (previously only reachable via getExtra()): verify the API's response // actually deserializes into them, not just that the code compiles. - assertEquals(task.getId(), wh.getCondition().get("actorTaskId").asText()); + assertEquals(task.getId(), wh.getCondition().get("actorTaskId").asString()); assertTrue(wh.getCreatedAt() != null); assertTrue(wh.getModifiedAt() != null); assertTrue(wh.getStats() != null);