chore: sync Java client with Apify OpenAPI spec v2-2026-07-10T105921Z; add iteration helpers and StreamedLog#6
Merged
Conversation
Forward-compatible spec update (error responses + relaxed nullability); version bump 0.1.3 -> 0.1.4. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Addresses review items: README Maven/Gradle install coordinates still pinned 0.1.3; CHANGELOG cited OpenAPI schema names as if Java classes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Adds iterate()/iterateItems()/iterateKeys() matching the reference JS iterable list(); shared PaginatedIterator engine; hermetic + integration tests; docs. Store.iterate signature change (limit = total cap, adds chunkSize) is breaking. Bumps client to 0.2.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
The API clamps over-large page sizes and some endpoints under-report (dataset items total=0), so short-page and total-based termination both truncate results. Advance offset by actual count and stop only on an empty page or the caller cap. Hardens hermetic tests with server-clamp scenarios and a terminating empty page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Remove stray cp.txt + gitignore it; add hermetic KeyIteratorTest; pattern-based offline CI test selection; client-side cap trim on both iterators; doc fixes (nested webhook list+iterate, paginateRequests exception, iterateKeys limit meaning, iterateItems filter caveat, normalized null-semantics, quick-start pom.xml, ActorRun statuses, write return types). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Move the iterateItems filter caveat blockquote after the DatasetClient table (it had split the table); run only *IntegrationTest in the integration CI step to avoid re-running hermetic tests; reflow a KVS comment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Extend the dataset-items iteration caveat (docs + Javadoc) to cover silent early-termination when an offset window is fully filtered out, not just the overlap/repeat mode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
…ests, docs) Publish workflow now selects hermetic tests by pattern (auto-includes new ones); add iterateKeys(options, chunkSize) overload for parity; hermetic test for the overshoot-trim branch; README quick start reads the token from the environment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Add hermetic tests for the iterateKeys(options, chunkSize) page-size and cap-combine paths; add convenience iterate(options) overloads across all collection clients and iterateItems for parity with iterateKeys; document the two-form iteration convention in the docs index. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
The (options, Class) overload clashed with (options, Long chunkSize), making iterateItems(opts, null) ambiguous. Drop it; typed iteration uses the 3-arg form. Add a hermetic test for the single-arg iterate delegation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Add DatasetItemsIteratorTest (MockBackend) covering iterateItems / fetchItemsPage: bare-array paging with empty-page termination, total-cap trim, and typed decoding — so the dataset-items path is gated offline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Avoids the raw-type in decodesIntoRequestedType. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Terminate key iteration on the API's isTruncated flag; normalize chunkSize in the PaginatedIterator constructor; reconcile the docs iteration note with the per-resource tables. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Iterators now snapshot the caller's filters at call time (matching the old copy() behavior), so mutating the options object mid-iteration no longer leaks into later pages. Align docs storage-name snippet with the runnable program's unique-name isolation. Add an isolation regression test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Actor-creation snippet uses a unique name (matching the storage snippet and runnable program); README no longer claims blanket item-equivalence across iterator forms, pointing to the iterateItems+filter caveat. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
…aveat Document that the client is on Maven Central and show mavenCentral() in the Gradle snippet; note that lastRun() RunClients are for reads and the mutating methods need a concrete run id. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Constructor already normalizes totalLimit/chunkSize to positive-or-null and capRemaining is always > 0 at the call site (exhausted guard), so the in-method > 0 re-checks were dead. Collapse to a plain null-aware min and document the input contract. No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
GET /v2/actors/{actorId}/versions takes no pagination params and returns
the full {total, items} list on every request (server ignores offset),
identical to the env-vars collection. Routing it through the offset/limit
PaginatedIterator looped forever (no limit) or duplicated items (with a
limit), since that engine only terminates on an empty page or the total
cap. Make iterate(ListOptions) a single fetch mirroring the env-vars
sibling, honoring the limit as a client-side cap and dropping the
meaningless chunkSize overload.
Correct CHANGELOG (Actor-version regrouped with env-vars as non-paginated)
and docs/actors.md. Integration test now fully drains the versions
iterator; add hermetic ReviewFixesTest regression tests that reproduce the
endpoint with a constant mock backend and assert single-fetch, exactly-once
iteration, and the limit cap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Add a parity note (docs/README.md Iteration section + ListOptions.limit Javadoc) that during iterate() a non-positive/zero limit means no cap, unlike list() which sends limit=0 verbatim. Note that the log-redirection example fragment throws a checked IOException and link the runnable LogRedirection.java. Documentation only; no behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Extend the list-vs-iterate limit(0) clarification to every options class that feeds an iterate helper (StorageListOptions, ActorListOptions, StoreListOptions, DatasetListItemsOptions, ListKeysOptions), since these are independent classes and do not inherit ListOptions' Javadoc. ListRequestsOptions is unchanged (it has no iterate overload). Docs only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
- Attribute checked IOException to transferTo(), not getStreamedLog() - Add "non-positive = no cap" nuance to all iterate Javadocs + doc tables - Reword README iteration note (drop "falsy"/untested server outcome) - Fix runs list signature note (RunListOptions) in README - Use absolute GitHub links for runnable example programs - Add return types to the TaskClient docs table - Note versions iterate ignores offset - Replace non-standard CHANGELOG "### Breaking" with Changed + bold prefix Documentation/Javadoc only; no runtime or public-interface change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
- ActorVersionCollectionClient: iterator is eager (single fetch), not lazy
- RunListOptions: correct startedAfter/startedBefore scoping per spec
- Add experimental/AI-generated disclaimer to all resource doc pages
- Retitle examples.md ("Examples") and stop overclaiming runnable
- KeyValueStoreClient.iterateKeys: page size left to server, bounded by limit
- Add DatasetClient.iterateItems(options, Class<T>) convenience overload + docs
- Move README imports note above the first quick-start fragment
Docs/Javadoc plus one additive (non-breaking) overload; no behavior change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Revert the iterateItems(options, Class<T>) overload re-added in 09b39b6: it reintroduces the iterateItems(opts, null) ambiguity that commit 02c977e removed. Typed default-page-size iteration uses the 3-arg form with a null chunk size (documented). Fix Javadoc/doc paths /v2/acts -> /v2/actors in RunListOptions and docs/webhooks.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
- Add experimental/AI-generated disclaimer to docs/examples.md - Update inbound link text "Runnable examples" -> "Examples" - Reorder README quick-start (source before compile) and align classpaths - Enumerate DownloadItemsFormat constants in docs/storages.md - Name the public com.apify.client.Version class in README Versioning - Add first-mention pointer for types used in the README quick-start Documentation only; no code or public-interface change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
The engine backs every offset/limit-paginated collection's iterate method; the cursor iterateKeys and single-fetch versions/env-vars iterators do not use it. Comment only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
…laimer Implement a StreamedLog helper (start/stop lifecycle, line-aware buffering, fromStart/toLog options, default per-run prefixed logger) matching the reference JS run.getStreamedLog(), returned by RunClient.getStreamedLog(). Update example (g), docs, and add hermetic + integration test coverage. Standardize the "official, but experimental" disclaimer across all doc pages. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
The final flush that emits StreamedLog's retained last message ran inside the try block, so a stop()-induced IOException from a blocked read() skipped it and the message was lost. Move the flush into finally so a stop still delivers it. Open the log stream in start() before launching the reader thread, eliminating a startup race where stop() closed a null stream and join() hung. Drop the redundant finally close now covered by try-with-resources. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Apply spotless formatting (test line exceeded 100 cols), document that start() now opens the stream synchronously and can throw ApifyApiException, reword the stream-close comment to reflect stop()'s idempotent close, and move MockBackend streaming fields to the field block. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
… doc placeholder - StreamedLog.close() is now synchronized and idempotent: running-check + stop happen atomically via a shared private stopStreaming(); close() never throws on a double/concurrent close while stop() keeps its explicit-misuse contract. - Rename ReviewFixesTest -> ClientBehaviourRegressionTest to name the behaviours it verifies rather than the review process; update stale reference comment. - docs/runs.md: use RUN_ID placeholder to match the UPPER_SNAKE convention. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Reword StreamedLogTest.closeAfterStopIsNoOp to describe sequential idempotency and add concurrentCloseNeverThrowsWhileStopRaces, which fires stop() and close() from two threads to pin that close() never throws under any interleaving. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Add a one-line description for each previously-undescribed field on DatasetListItemsOptions, StoreListOptions, and ActorStartOptions, matching the repo's inline field-description style. Semantics verified against the option classes' setter Javadoc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
…ailure Guard stopStreaming() against a thread joining itself: the toLog consumer runs on the reader thread, so stop()/close() from inside it would join the thread on itself and hang forever while holding the synchronized monitor. Wrap the default log-prefix lookup (two synchronous GETs at helper construction) in try/catch, falling back to the runId-only prefix so a 401/403/5xx on the cosmetic lookup no longer aborts getStreamedLog(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Document that stop() joins the reader only when called from another thread; a self-call from inside the consumer skips the join and returns immediately, and a repeat self-stop throws because the reader's final flush may re-invoke the consumer. Steer consumer-driven self-termination to the idempotent close(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Guard destination.accept() so a throwing user consumer is caught and logged at WARNING (matching the JS reference) instead of escaping as an uncaught daemon-thread exception. Make the pending-message buffer local to each reader run so a start() racing a still-draining self-stopped reader cannot corrupt shared non-thread-safe parsing state. Also align docs: getStatistics() shown as Optional<JsonNode> in the index, store() cross-references StoreCollectionClient, and the account example documents getExtra() for non-modelled fields. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
Introduce a forwardingFailed flag so a throwing destination consumer is invoked exactly once: the emit loop returns on the first failure and the final flush is skipped, logging a single warning and delivering nothing further (matching the JS reference). Condense and correct the catch-block comment. Tighten the hermetic test to assert exactly-once invocation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkZYoebybdnv7MFH9Ua6E
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Syncs the Java client to Apify OpenAPI spec
v2-2026-07-10T105921Z, adds lazy iteration helpers across all collections, and adds aStreamedLoglog-redirection helper. Version bumped to0.3.0.Added
iterate(...)), plusDatasetClient.iterateItems(...)andKeyValueStoreClient.iterateKeys(...), backed by a sharedPaginatedIterator.limitcaps total items yielded (matching the reference); page size is a separatechunkSizeargument.RequestQueueClient.paginateRequests(...)mirrors the reference cursor iterator.StreamedLoglog-redirection helper:RunClient.getStreamedLog()/getStreamedLog(StreamedLogOptions)return anAutoCloseableStreamedLogthat follows the run's live log in a background thread and redirects each complete, timestamped message to a destination (default a per-run-prefixedjava.util.logginglogger). Options:toLog(Consumer<String>),prefix(String),fromStart(boolean).Changed
v2-2026-07-10T105921Zand version to0.3.0.RunClient.getStreamedLog()now returns aStreamedLoghelper instead of a rawInputStream(for raw access userun(id).log().stream(new LogOptions().raw(true))).StoreCollectionClient.iteratenow takes achunkSizeargument withlimitredefined as a total-item cap.Fixed (StreamedLog robustness)
finally).stop()/close()can no longer hang on a startup race (stream opened instart()before the reader launches);close()is fully idempotent; a consumer callingstop()/close()on itself no longer self-joins/deadlocks.Documentation
StreamedLoglifecycle, and alignedgetStatistics()/store()type references.See
CHANGELOG.mdfor the full[0.2.0]/[0.3.0]entries.Generated by Claude Code