From 438df4c05514bbd99e0bf6f1ba156fa3521744e5 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Mon, 19 Oct 2026 12:31:12 -0700 Subject: [PATCH 01/17] Add workflow-side signal-with-start through system Nexus --- temporal-sdk/build.gradle | 35 + .../common/converter/CodecDataConverter.java | 34 +- .../WorkflowOutboundCallsInterceptor.java | 3 +- .../WorkflowOutboundCallsInterceptorBase.java | 9 +- .../system/SystemNexusDataConverter.java | 84 ++ .../nexus/system/TemporalModelConverters.java | 161 ++++ .../internal/sync/NexusServiceStubImpl.java | 14 +- ...nalWithStartWorkflowInvocationHandler.java | 145 ++++ .../sync/SignalWithStartWorkflowStubImpl.java | 96 +++ .../internal/sync/SyncWorkflowContext.java | 24 +- .../system/workflowservice/NexgenRuntime.java | 306 +++++++ .../SignalWithStartWorkflowRequest.java | 750 ++++++++++++++++++ .../SignalWithStartWorkflowResponse.java | 139 ++++ .../SystemNexusOperations.java | 40 + ...ystemNexusWorkflowOutboundInterceptor.java | 41 + .../system/workflowservice/UserMetadata.java | 132 +++ .../workflowservice/WorkflowService.java | 9 + .../WorkflowServiceOperations.java | 38 + .../workflowservice/system-nexus-roots.txt | 2 + .../SignalWithStartWorkflowOptions.java | 226 ++++++ .../workflow/SignalWithStartWorkflowStub.java | 19 + .../java/io/temporal/workflow/Workflow.java | 27 + temporal-sdk/src/main/nexus/README.md | 23 + .../src/main/nexus/SIGNAL_WITH_START.md | 35 + .../nexus/deps/nexus-temporal-types/model.wit | 196 +++++ .../src/main/nexus/workflow-service.wit | 129 +++ .../system/SystemNexusDataConverterTest.java | 225 ++++++ .../storage/ExternalStorageRunnerTest.java | 28 + .../nexus/SignalWithStartWorkflowTest.java | 150 ++++ .../SystemSignalWithStartIntegrationTest.java | 91 +++ temporal-serviceclient/build.gradle | 6 +- .../payload/visitor/SystemNexusPayloads.java | 47 ++ .../internal/payload/visitor/Traversal.java | 31 + .../internal/payload/gen/ProtoClosure.java | 20 + .../visitor/gen/PayloadVisitorGenerator.java | 50 +- .../payload/gen/ProtoClosureRootTest.java | 54 ++ .../visitor/SystemNexusPayloadTest.java | 96 +++ 37 files changed, 3491 insertions(+), 24 deletions(-) create mode 100644 temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java create mode 100644 temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java create mode 100644 temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowInvocationHandler.java create mode 100644 temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowStubImpl.java create mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/NexgenRuntime.java create mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowRequest.java create mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowResponse.java create mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusOperations.java create mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusWorkflowOutboundInterceptor.java create mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/UserMetadata.java create mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowService.java create mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowServiceOperations.java create mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/system-nexus-roots.txt create mode 100644 temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowOptions.java create mode 100644 temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowStub.java create mode 100644 temporal-sdk/src/main/nexus/README.md create mode 100644 temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md create mode 100644 temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit create mode 100644 temporal-sdk/src/main/nexus/workflow-service.wit create mode 100644 temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java create mode 100644 temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java create mode 100644 temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java create mode 100644 temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java create mode 100644 temporal-serviceclient/src/test/java/io/temporal/internal/payload/gen/ProtoClosureRootTest.java create mode 100644 temporal-serviceclient/src/test/java/io/temporal/internal/payload/visitor/SystemNexusPayloadTest.java diff --git a/temporal-sdk/build.gradle b/temporal-sdk/build.gradle index d74bb1c7cc..49e378ad6b 100644 --- a/temporal-sdk/build.gradle +++ b/temporal-sdk/build.gradle @@ -335,3 +335,38 @@ tasks.named('check') { dependsOn(testing.suites.jackson3Tests) dependsOn(testing.suites.virtualThreadTests) } + +// Explicit regeneration keeps normal SDK builds independent of the Rust toolchain. +// Use -PnexgenBinary=/path/to/nexgen to test an unreleased generator. +def nexusGeneratedDir = layout.buildDirectory.dir('generated/nexus/workflowservice').get().asFile +def nexusCheckedInDir = file('src/main/java/io/temporal/nexus/system/workflowservice') +tasks.register('generateNexusSystemApi', Exec) { + dependsOn ':temporal-serviceclient:generateProto' + def binary = providers.gradleProperty('nexgenBinary').orElse('nexgen') + inputs.dir('src/main/nexus') + inputs.file(project(':temporal-serviceclient').layout.buildDirectory.file('generated/descriptors/temporal-api.desc')) + inputs.property('nexgenVersion', '0.2.9') + outputs.dir(nexusGeneratedDir) + outputs.upToDateWhen { false } + commandLine binary.get(), 'java', file('src/main/nexus/workflow-service.wit'), + file('src/main/nexus/deps'), '--native-api', '--system-nexus', + '--support-package', 'io.temporal.internal.nexus.system.TemporalModelConverters', + '--package-name', 'io.temporal.nexus.system.workflowservice', + '--descriptors', project(':temporal-serviceclient').layout.buildDirectory.file('generated/descriptors/temporal-api.desc').get().asFile, + '--output', nexusGeneratedDir + doFirst { + def versionOutput = new ByteArrayOutputStream() + project.exec { invocation -> + invocation.commandLine(binary.get(), '--version') + invocation.standardOutput = versionOutput + } + if (versionOutput.toString('UTF-8').trim() != 'nexgen 0.2.9') { + throw new GradleException('System Nexus regeneration requires nexgen 0.2.9 with the advanced feature.') + } + delete nexusGeneratedDir + } + doLast { project.sync { spec -> spec.from(nexusGeneratedDir); spec.into(nexusCheckedInDir) } } +} +tasks.matching { it.name == 'compileJava' || it.name.startsWith('spotless') }.configureEach { + mustRunAfter 'generateNexusSystemApi' +} diff --git a/temporal-sdk/src/main/java/io/temporal/common/converter/CodecDataConverter.java b/temporal-sdk/src/main/java/io/temporal/common/converter/CodecDataConverter.java index a82172348b..bc0a15021c 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/converter/CodecDataConverter.java +++ b/temporal-sdk/src/main/java/io/temporal/common/converter/CodecDataConverter.java @@ -113,18 +113,14 @@ public CodecDataConverter( public Optional toPayload(T value) { Optional payload = ConverterUtils.withContext(dataConverter, serializationContext).toPayload(value); - List encodedPayloads = - ConverterUtils.withContext(chainCodec, serializationContext) - .encode(Collections.singletonList(payload.get())); + List encodedPayloads = encode(Collections.singletonList(payload.get())); Preconditions.checkState(encodedPayloads.size() == 1, "Expected one encoded payload"); return Optional.of(encodedPayloads.get(0)); } @Override public T fromPayload(Payload payload, Class valueClass, Type valueType) { - List decodedPayload = - ConverterUtils.withContext(chainCodec, serializationContext) - .decode(Collections.singletonList(payload)); + List decodedPayload = decode(Collections.singletonList(payload)); Preconditions.checkState(decodedPayload.size() == 1, "Expected one decoded payload"); return ConverterUtils.withContext(dataConverter, serializationContext) .fromPayload(decodedPayload.get(0), valueClass, valueType); @@ -135,9 +131,7 @@ public Optional toPayloads(Object... values) throws DataConverterExcep Optional payloads = ConverterUtils.withContext(dataConverter, serializationContext).toPayloads(values); if (payloads.isPresent()) { - List encodedPayloads = - ConverterUtils.withContext(chainCodec, serializationContext) - .encode(payloads.get().getPayloadsList()); + List encodedPayloads = encode(payloads.get().getPayloadsList()); payloads = Optional.of(Payloads.newBuilder().addAllPayloads(encodedPayloads).build()); } return payloads; @@ -193,13 +187,31 @@ public CodecDataConverter withContext(@Nonnull SerializationContext context) { @Nonnull @Override public List encode(@Nonnull List payloads) { - return ConverterUtils.withContext(chainCodec, serializationContext).encode(payloads); + return visitSystemEnvelopes(payloads, true); } @Nonnull @Override public List decode(@Nonnull List payloads) { - return ConverterUtils.withContext(chainCodec, serializationContext).decode(payloads); + return visitSystemEnvelopes(payloads, false); + } + + private List visitSystemEnvelopes(List payloads, boolean encode) { + PayloadCodec codec = ConverterUtils.withContext(chainCodec, serializationContext); + if (payloads.stream() + .noneMatch(io.temporal.internal.payload.visitor.SystemNexusPayloads::isSystemPayload)) { + return encode ? codec.encode(payloads) : codec.decode(payloads); + } + return io.temporal.internal.payload.visitor.PayloadVisitors.visit( + Payloads.newBuilder().addAllPayloads(payloads).build(), + io.temporal.internal.payload.visitor.PayloadVisitorOptions.newBuilder( + (context, nested) -> + java.util.concurrent.CompletableFuture.completedFuture( + encode ? codec.encode(nested) : codec.decode(nested))) + .setSkipSearchAttributes(true) + .build()) + .join() + .getPayloadsList(); } private Failure.Builder encodeFailure(Failure.Builder failure) { diff --git a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java index a1b581a4e5..894f983649 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java +++ b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java @@ -37,7 +37,8 @@ * WorkflowInboundCallsInterceptor. */ @Experimental -public interface WorkflowOutboundCallsInterceptor { +public interface WorkflowOutboundCallsInterceptor + extends io.temporal.nexus.system.workflowservice.SystemNexusWorkflowOutboundInterceptor { final class ActivityInput { private final String activityName; diff --git a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java index 6f55f2f4ae..fb55fbb354 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java +++ b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java @@ -16,10 +16,17 @@ import java.util.function.Supplier; /** Convenience base class for WorkflowOutboundCallsInterceptor implementations. */ -public class WorkflowOutboundCallsInterceptorBase implements WorkflowOutboundCallsInterceptor { +public class WorkflowOutboundCallsInterceptorBase + extends io.temporal.nexus.system.workflowservice.SystemNexusWorkflowOutboundInterceptor.Base + implements WorkflowOutboundCallsInterceptor { private final WorkflowOutboundCallsInterceptor next; + @Override + protected WorkflowOutboundCallsInterceptor nextSystemNexusInterceptor() { + return next; + } + public WorkflowOutboundCallsInterceptorBase(WorkflowOutboundCallsInterceptor next) { this.next = next; } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java new file mode 100644 index 0000000000..37671df6c6 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java @@ -0,0 +1,84 @@ +package io.temporal.internal.nexus.system; + +import com.google.protobuf.Message; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.common.v1.Payloads; +import io.temporal.api.failure.v1.Failure; +import io.temporal.common.converter.DataConverter; +import io.temporal.common.converter.DataConverterException; +import io.temporal.common.converter.RawValue; +import io.temporal.internal.common.converter.TemporalTransferTypeDataConverter; +import io.temporal.internal.payload.visitor.SystemNexusPayloads; +import io.temporal.nexus.system.workflowservice.NexgenRuntime; +import java.lang.reflect.Type; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** Keeps the server-readable envelope separate from the destination workflow's user converter. */ +public final class SystemNexusDataConverter implements DataConverter { + public static final String ENDPOINT = "__temporal_system"; + private final DataConverter userConverter; + + public SystemNexusDataConverter(DataConverter userConverter) { + this.userConverter = userConverter; + } + + @Override + public Optional toPayload(T value) { + if (value instanceof RawValue) return Optional.of(((RawValue) value).getPayload()); + return NexgenRuntime.withDataConverter( + userConverter, + () -> { + Object transferred = TemporalTransferTypeDataConverter.toTransferValue(value); + if (!(transferred instanceof Message)) + throw new DataConverterException( + "System Nexus inputs must have a protobuf transfer type"); + return Optional.of(SystemNexusPayloads.pack((Message) transferred)); + }); + } + + @Override + public T fromPayload(Payload payload, Class valueClass, Type valueType) { + if (valueClass == RawValue.class) return valueClass.cast(new RawValue(payload)); + return NexgenRuntime.withDataConverter( + userConverter, + () -> { + Message value = SystemNexusPayloads.unpack(payload).build(); + TemporalTransferTypeDataConverter.TransferType transfer = + TemporalTransferTypeDataConverter.transferTypeFor(valueClass, valueType); + if (transfer == null) return valueClass.cast(value); + if (!transfer.getRawType().isInstance(value)) + throw new DataConverterException( + "Unexpected system Nexus response type: " + + value.getDescriptorForType().getFullName()); + return transfer.fromValue(value, valueClass); + }); + } + + @Override + public Optional toPayloads(Object... values) { + if (values == null || values.length == 0) return Optional.empty(); + Payloads.Builder result = Payloads.newBuilder(); + for (Object value : values) result.addPayloads(toPayload(value).get()); + return Optional.of(result.build()); + } + + @Override + public T fromPayloads( + int index, Optional values, Class valueClass, Type valueType) { + if (!values.isPresent() || index >= values.get().getPayloadsCount()) return null; + return fromPayload(values.get().getPayloads(index), valueClass, valueType); + } + + @Nonnull + @Override + public RuntimeException failureToException(@Nonnull Failure failure) { + return userConverter.failureToException(failure); + } + + @Nonnull + @Override + public Failure exceptionToFailure(@Nonnull Throwable failure) { + return userConverter.exceptionToFailure(failure); + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java new file mode 100644 index 0000000000..30cdb3e249 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -0,0 +1,161 @@ +package io.temporal.internal.nexus.system; + +import io.temporal.api.common.v1.*; +import io.temporal.api.taskqueue.v1.TaskQueue; +import io.temporal.common.RetryOptions; +import io.temporal.common.VersioningOverride; +import io.temporal.common.converter.DataConverter; +import io.temporal.internal.common.*; +import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest; +import io.temporal.payload.context.WorkflowSerializationContext; +import io.temporal.workflow.Workflow; +import java.time.Duration; +import java.util.LinkedHashMap; +import java.util.Map; + +/** SDK-owned model conversion hooks used by the generated system Nexus bindings. */ +public final class TemporalModelConverters { + private TemporalModelConverters() {} + + public static String workflowNamespace() { + return Workflow.getInfo().getNamespace(); + } + + public static WorkflowSerializationContext signalWithStartWorkflowSerializationContext( + SignalWithStartWorkflowRequest request) { + return new WorkflowSerializationContext(request.getNamespace(), request.getId()); + } + + public static RuntimeException failureFromProto( + DataConverter converter, io.temporal.api.failure.v1.Failure value) { + return converter.failureToException(value); + } + + public static io.temporal.api.failure.v1.Failure failureToProto( + DataConverter converter, RuntimeException value) { + return converter.exceptionToFailure(value); + } + + public static WorkflowType workflowTypeToProto(DataConverter converter, String value) { + return WorkflowType.newBuilder().setName(value).build(); + } + + public static String workflowTypeFromProto(DataConverter converter, WorkflowType value) { + return value.getName(); + } + + public static TaskQueue taskQueueToProto(DataConverter converter, String value) { + return TaskQueue.newBuilder().setName(value).build(); + } + + public static String taskQueueFromProto(DataConverter converter, TaskQueue value) { + return value.getName(); + } + + public static com.google.protobuf.Duration durationToProto( + DataConverter converter, Duration value) { + return ProtobufTimeUtils.toProtoDuration(value); + } + + public static Duration durationFromProto( + DataConverter converter, com.google.protobuf.Duration value) { + return ProtobufTimeUtils.toJavaDuration(value); + } + + public static RetryPolicy retryPolicyToProto(DataConverter converter, RetryOptions value) { + return RetryOptionsUtils.toRetryPolicy(value).build(); + } + + public static RetryOptions retryPolicyFromProto(DataConverter converter, RetryPolicy value) { + return RetryOptionsUtils.toRetryOptions(value); + } + + public static Memo memoToProto(DataConverter converter, Map value) { + Memo.Builder builder = Memo.newBuilder(); + value.forEach((key, item) -> builder.putFields(key, converter.toPayload(item).get())); + return builder.build(); + } + + public static Map memoFromProto(DataConverter converter, Memo value) { + Map result = new LinkedHashMap<>(); + value + .getFieldsMap() + .forEach( + (key, payload) -> + result.put(key, converter.fromPayload(payload, Object.class, Object.class))); + return result; + } + + public static Header headerToProto(DataConverter converter, Map value) { + Header.Builder builder = Header.newBuilder(); + value.forEach( + (key, payload) -> + builder.putFields( + key, + converter.toPayload(new io.temporal.common.converter.RawValue(payload)).get())); + return builder.build(); + } + + public static Map headerFromProto(DataConverter converter, Header value) { + Map result = new LinkedHashMap<>(); + value + .getFieldsMap() + .forEach( + (key, payload) -> + result.put( + key, + converter + .fromPayload( + payload, + io.temporal.common.converter.RawValue.class, + io.temporal.common.converter.RawValue.class) + .getPayload())); + return result; + } + + public static io.temporal.api.common.v1.SearchAttributes searchAttributesToProto( + DataConverter converter, io.temporal.common.SearchAttributes value) { + return SearchAttributesUtil.encodeTyped(value); + } + + public static io.temporal.common.SearchAttributes searchAttributesFromProto( + DataConverter converter, io.temporal.api.common.v1.SearchAttributes value) { + return SearchAttributesUtil.decodeTyped(value); + } + + public static Priority priorityToProto( + DataConverter converter, io.temporal.common.Priority value) { + return ProtoConverters.toProto(value); + } + + public static io.temporal.common.Priority priorityFromProto( + DataConverter converter, Priority value) { + return ProtoConverters.fromProto(value); + } + + public static io.temporal.api.workflow.v1.VersioningOverride versioningOverrideToProto( + DataConverter converter, VersioningOverride value) { + return ProtoConverters.toProto(value); + } + + @SuppressWarnings("deprecation") + public static VersioningOverride versioningOverrideFromProto( + DataConverter converter, io.temporal.api.workflow.v1.VersioningOverride value) { + if (value.hasOneTime()) + return new VersioningOverride.OneTimeVersioningOverride( + deployment(value.getOneTime().getTargetDeploymentVersion())); + if (value.hasPinned()) + return new VersioningOverride.PinnedVersioningOverride( + deployment(value.getPinned().getVersion())); + if (!value.getPinnedVersion().isEmpty()) + return new VersioningOverride.PinnedVersioningOverride( + io.temporal.common.WorkerDeploymentVersion.fromCanonicalString(value.getPinnedVersion())); + return new VersioningOverride.AutoUpgradeVersioningOverride(); + } + + private static io.temporal.common.WorkerDeploymentVersion deployment( + io.temporal.api.deployment.v1.WorkerDeploymentVersion value) { + return new io.temporal.common.WorkerDeploymentVersion( + value.getDeploymentName(), value.getBuildId()); + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java index 821b92f075..c1dd41479f 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java @@ -61,7 +61,7 @@ public Promise executeAsync( .mergeNexusOperationOptions(options.getOperationMethodOptions().get(operationName)) .build(); WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput result = - outboundCallsInterceptor.executeNexusOperation( + executeNexusOperation( new WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput<>( options.getEndpoint(), name, @@ -88,7 +88,7 @@ public NexusOperationHandle start( .mergeNexusOperationOptions(options.getOperationMethodOptions().get(operationName)) .build(); WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput result = - outboundCallsInterceptor.executeNexusOperation( + executeNexusOperation( new WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput<>( options.getEndpoint(), name, @@ -101,6 +101,16 @@ public NexusOperationHandle start( return new NexusOperationHandleImpl<>(result.getOperationExecution(), result.getResult()); } + private WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput executeNexusOperation( + WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input) { + if (io.temporal.internal.nexus.system.SystemNexusDataConverter.ENDPOINT.equals( + input.getEndpoint())) { + return io.temporal.nexus.system.workflowservice.SystemNexusOperations.execute( + outboundCallsInterceptor, input); + } + return outboundCallsInterceptor.executeNexusOperation(input); + } + @Override public NexusServiceOptions getOptions() { return options; diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowInvocationHandler.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowInvocationHandler.java new file mode 100644 index 0000000000..cb5f60a8e9 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowInvocationHandler.java @@ -0,0 +1,145 @@ +package io.temporal.internal.sync; + +import com.google.common.base.Defaults; +import io.temporal.common.CronSchedule; +import io.temporal.common.MethodRetry; +import io.temporal.common.RetryOptions; +import io.temporal.common.metadata.POJOWorkflowInterfaceMetadata; +import io.temporal.common.metadata.POJOWorkflowMethodMetadata; +import io.temporal.common.metadata.WorkflowMethodType; +import io.temporal.workflow.*; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** Captures two typed calls without executing either one before validation completes. */ +public final class SignalWithStartWorkflowInvocationHandler implements InvocationHandler { + private static final ThreadLocal CURRENT = new ThreadLocal<>(); + private final Class workflowInterface; + private final POJOWorkflowInterfaceMetadata metadata; + private final SignalWithStartWorkflowStub stub; + + private SignalWithStartWorkflowInvocationHandler( + Class workflowInterface, SignalWithStartWorkflowOptions options) { + this.workflowInterface = workflowInterface; + metadata = POJOWorkflowInterfaceMetadata.newInstance(workflowInterface); + POJOWorkflowMethodMetadata workflow = + metadata + .getWorkflowMethod() + .orElseThrow( + () -> + new IllegalArgumentException("Missing method annotated with @WorkflowMethod")); + Method method = workflow.getWorkflowMethod(); + SignalWithStartWorkflowOptions base = + options == null ? SignalWithStartWorkflowOptions.newBuilder().build() : options; + MethodRetry retry = method.getAnnotation(MethodRetry.class); + CronSchedule cron = method.getAnnotation(CronSchedule.class); + SignalWithStartWorkflowOptions merged = + base.toBuilder() + .setRetryOptions(RetryOptions.merge(retry, base.getRetryOptions())) + .setCronSchedule( + base.getCronSchedule() == null && cron != null + ? cron.value() + : base.getCronSchedule()) + .build(); + stub = new SignalWithStartWorkflowStubImpl(workflow.getName(), merged); + } + + @SuppressWarnings("unchecked") + public static T newStub(Class workflowInterface, SignalWithStartWorkflowOptions options) { + return (T) + Proxy.newProxyInstance( + workflowInterface.getClassLoader(), + new Class[] {workflowInterface}, + new SignalWithStartWorkflowInvocationHandler(workflowInterface, options)); + } + + private static SignalWithStartWorkflowInvocationHandler handler(Object target) { + if (target == null + || !Proxy.isProxyClass(target.getClass()) + || !(Proxy.getInvocationHandler(target) + instanceof SignalWithStartWorkflowInvocationHandler)) { + throw new IllegalArgumentException( + "Expected a stub created through Workflow.newSignalWithStartWorkflowStub"); + } + return (SignalWithStartWorkflowInvocationHandler) Proxy.getInvocationHandler(target); + } + + public static SignalWithStartWorkflowStub fromTyped(Object target) { + return handler(target).stub; + } + + @SuppressWarnings("unchecked") + public static T signalWithStart( + T target, Functions.Proc workflowCall, Functions.Proc signalCall) { + SignalWithStartWorkflowInvocationHandler handler = handler(target); + if (CURRENT.get() != null) + throw new IllegalStateException("Nested signal-with-start capture is not supported"); + Capture capture = new Capture(handler); + CURRENT.set(capture); + try { + workflowCall.apply(); + if (capture.startArgs == null) + throw new IllegalArgumentException("Expected exactly one workflow call"); + capture.signalPhase = true; + signalCall.apply(); + if (capture.signalArgs == null) + throw new IllegalArgumentException("Expected exactly one signal call"); + } finally { + CURRENT.remove(); + } + ExternalWorkflowStub external = + handler.stub.signalWithStart(capture.signalName, capture.signalArgs, capture.startArgs); + return (T) Workflow.newExternalWorkflowStub(handler.workflowInterface, external.getExecution()); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + if (method.getDeclaringClass() == Object.class) { + switch (method.getName()) { + case "toString": + return "SignalWithStartWorkflowStub{" + stub.getWorkflowType() + "}"; + case "hashCode": + return System.identityHashCode(proxy); + case "equals": + return proxy == args[0]; + default: + throw new IllegalArgumentException("Unsupported Object method"); + } + } + Capture capture = CURRENT.get(); + if (capture == null || capture.handler != this) + throw new IllegalStateException( + "Calls must use the target stub inside Workflow.signalWithStart"); + POJOWorkflowMethodMetadata entry = metadata.getMethodMetadata(method); + Object[] values = args == null ? new Object[0] : args.clone(); + if (!capture.signalPhase + && entry.getType() == WorkflowMethodType.WORKFLOW + && capture.startArgs == null) { + capture.startArgs = values; + } else if (capture.signalPhase + && entry.getType() == WorkflowMethodType.SIGNAL + && capture.signalArgs == null) { + capture.signalName = entry.getName(); + capture.signalArgs = values; + } else { + throw new IllegalArgumentException( + "Capture requires exactly one workflow call followed by exactly one signal call"); + } + return method.getReturnType() == Void.TYPE + ? null + : Defaults.defaultValue(method.getReturnType()); + } + + private static final class Capture { + private final SignalWithStartWorkflowInvocationHandler handler; + private boolean signalPhase; + private Object[] startArgs; + private String signalName; + private Object[] signalArgs; + + private Capture(SignalWithStartWorkflowInvocationHandler handler) { + this.handler = handler; + } + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowStubImpl.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowStubImpl.java new file mode 100644 index 0000000000..215be6b386 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowStubImpl.java @@ -0,0 +1,96 @@ +package io.temporal.internal.sync; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.WorkflowIdReusePolicy; +import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest; +import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse; +import io.temporal.nexus.system.workflowservice.UserMetadata; +import io.temporal.nexus.system.workflowservice.WorkflowServiceOperations; +import io.temporal.workflow.*; +import java.util.Arrays; +import java.util.Objects; + +public final class SignalWithStartWorkflowStubImpl implements SignalWithStartWorkflowStub { + private final String workflowType; + private final SignalWithStartWorkflowOptions options; + + public SignalWithStartWorkflowStubImpl( + String workflowType, SignalWithStartWorkflowOptions options) { + this.workflowType = Objects.requireNonNull(workflowType, "workflowType"); + this.options = options == null ? SignalWithStartWorkflowOptions.newBuilder().build() : options; + } + + @Override + public String getWorkflowType() { + return workflowType; + } + + @Override + public SignalWithStartWorkflowOptions getOptions() { + return options; + } + + @SuppressWarnings("deprecation") + @Override + public ExternalWorkflowStub signalWithStart( + String signalName, Object[] signalArgs, Object... startArgs) { + WorkflowInternal.assertNotReadOnly("signal with start workflow"); + if (workflowType.isEmpty()) + throw new IllegalArgumentException("workflowType must not be empty"); + if (signalName == null || signalName.isEmpty()) + throw new IllegalArgumentException("signalName must not be empty"); + String id = + options.getWorkflowId() == null + ? Workflow.randomUUID().toString() + : options.getWorkflowId(); + if (id.isEmpty()) throw new IllegalArgumentException("workflowId must not be empty"); + String queue = + options.getTaskQueue() == null ? Workflow.getInfo().getTaskQueue() : options.getTaskQueue(); + if (queue.isEmpty()) throw new IllegalArgumentException("taskQueue must not be empty"); + if (options.getWorkflowIdReusePolicy() + == WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING + && options.getWorkflowIdConflictPolicy() != null) { + throw new IllegalArgumentException( + "workflowIdConflictPolicy cannot be combined with terminate-if-running"); + } + SignalWithStartWorkflowRequest request = + SignalWithStartWorkflowRequest.newBuilder() + .setWorkflow(workflowType) + .setSignal(signalName) + .setId(id) + .setTaskQueue(queue) + .setArgs(Arrays.asList(startArgs == null ? new Object[0] : startArgs.clone())) + .setSignalArgs(Arrays.asList(signalArgs == null ? new Object[0] : signalArgs.clone())) + .setExecutionTimeout(options.getWorkflowExecutionTimeout()) + .setRunTimeout(options.getWorkflowRunTimeout()) + .setTaskTimeout(options.getWorkflowTaskTimeout()) + .setIdReusePolicy( + options.getWorkflowIdReusePolicy() == null + ? WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE + : options.getWorkflowIdReusePolicy()) + .setIdConflictPolicy(options.getWorkflowIdConflictPolicy()) + .setRetryPolicy(options.getRetryOptions()) + .setCronSchedule(options.getCronSchedule()) + .setMemo(options.getMemo()) + .setSearchAttributes(options.getTypedSearchAttributes()) + .setPriority(options.getPriority()) + .setVersioningOverride(options.getVersioningOverride()) + .setStartDelay(options.getStartDelay()) + .setRequestId( + options.getRequestId() == null + ? Workflow.randomUUID().toString() + : options.getRequestId()) + .setUserMetadata( + UserMetadata.newBuilder() + .setStaticSummary(options.getStaticSummary()) + .setStaticDetails(options.getStaticDetails()) + .build()) + .build(); + SignalWithStartWorkflowResponse response = + WorkflowServiceOperations.signalWithStartWorkflow(request); + WorkflowExecution.Builder execution = WorkflowExecution.newBuilder().setWorkflowId(id); + if (response.getRunId() != null && !response.getRunId().isEmpty()) + execution.setRunId(response.getRunId()); + return Workflow.newUntypedExternalWorkflowStub(execution.build()); + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java index 2d5cfcba33..cfba04d403 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java @@ -828,10 +828,24 @@ public ExecuteNexusOperationOutput executeNexusOperation( // contextualized by the endpoint, service and operation instead. The same converter decodes the // result and converts failures, so each operation keeps the converter selected for it even when // several operations are in flight at once. - DataConverter nexusDataConverter = - dataConverter.withContext( - new NexusSerializationContext( - input.getEndpoint(), input.getService(), input.getOperation())); + final DataConverter nexusDataConverter; + final DataConverter userMetadataDataConverter; + if (io.temporal.internal.nexus.system.SystemNexusDataConverter.ENDPOINT.equals( + input.getEndpoint())) { + io.temporal.payload.context.SerializationContext context = + io.temporal.nexus.system.workflowservice.SystemNexusOperations.serializationContext( + input.getService(), input.getOperation(), input.getArg()); + userMetadataDataConverter = + context == null ? dataConverter : dataConverter.withContext(context); + nexusDataConverter = + new io.temporal.internal.nexus.system.SystemNexusDataConverter(userMetadataDataConverter); + } else { + nexusDataConverter = + dataConverter.withContext( + new NexusSerializationContext( + input.getEndpoint(), input.getService(), input.getOperation())); + userMetadataDataConverter = nexusDataConverter; + } Optional payload = nexusDataConverter.toPayload(input.getArg()); @@ -852,7 +866,7 @@ public ExecuteNexusOperationOutput executeNexusOperation( @Nullable UserMetadata userMetadata = - makeUserMetaData(input.getOptions().getSummary(), null, nexusDataConverter); + makeUserMetaData(input.getOptions().getSummary(), null, userMetadataDataConverter); StartNexusOperationParameters parameters = new StartNexusOperationParameters( diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/NexgenRuntime.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/NexgenRuntime.java new file mode 100644 index 0000000000..f001d56b23 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/NexgenRuntime.java @@ -0,0 +1,306 @@ +// Generated by nexgen. DO NOT EDIT! +package io.temporal.nexus.system.workflowservice; + +/** Shared conversion helpers for generated WIT models. */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class NexgenRuntime { + private NexgenRuntime() {} + + private static final ThreadLocal CONVERTER = + new ThreadLocal<>(); + + public static io.temporal.common.converter.DataConverter dataConverter() { + io.temporal.common.converter.DataConverter value = CONVERTER.get(); + return value == null + ? io.temporal.common.converter.DefaultDataConverter.STANDARD_INSTANCE + : value; + } + + public static T withDataConverter( + io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { + io.temporal.common.converter.DataConverter previous = CONVERTER.get(); + CONVERTER.set(converter); + try { + return action.get(); + } finally { + if (previous == null) CONVERTER.remove(); + else CONVERTER.set(previous); + } + } + + public static java.lang.reflect.Type parameterized( + final Class raw, final java.lang.reflect.Type... arguments) { + return new java.lang.reflect.ParameterizedType() { + public java.lang.reflect.Type getRawType() { + return raw; + } + + public java.lang.reflect.Type getOwnerType() { + return raw.getDeclaringClass(); + } + + public java.lang.reflect.Type[] getActualTypeArguments() { + return arguments.clone(); + } + }; + } + + public static java.lang.reflect.Type argument(java.lang.reflect.Type type, int index) { + return type instanceof java.lang.reflect.ParameterizedType + ? ((java.lang.reflect.ParameterizedType) type).getActualTypeArguments()[index] + : Object.class; + } + + public static Object get(com.google.protobuf.Message message, String name) { + return message.getField(field(message, name)); + } + + public static boolean has(com.google.protobuf.Message message, String name) { + com.google.protobuf.Descriptors.FieldDescriptor field = field(message, name); + return field.isRepeated() ? message.getRepeatedFieldCount(field) > 0 : message.hasField(field); + } + + private static com.google.protobuf.Descriptors.FieldDescriptor field( + com.google.protobuf.MessageOrBuilder message, String name) { + com.google.protobuf.Descriptors.FieldDescriptor field = + message.getDescriptorForType().findFieldByName(name); + if (field == null) throw new IllegalArgumentException("Unknown protobuf field: " + name); + return field; + } + + public static void set(com.google.protobuf.Message.Builder builder, String name, Object value) { + com.google.protobuf.Descriptors.FieldDescriptor field = field(builder, name); + if (field.isMapField() && value instanceof java.util.Map) { + for (Object raw : ((java.util.Map) value).entrySet()) { + java.util.Map.Entry entry = (java.util.Map.Entry) raw; + com.google.protobuf.Message.Builder entryBuilder = builder.newBuilderForField(field); + set(entryBuilder, "key", entry.getKey()); + set(entryBuilder, "value", entry.getValue()); + builder.addRepeatedField(field, entryBuilder.build()); + } + } else if (field.isRepeated()) { + java.util.List normalized = new java.util.ArrayList<>(); + for (Object item : (java.util.List) value) normalized.add(wireValue(field, item)); + builder.setField(field, normalized); + } else { + builder.setField(field, wireValue(field, value)); + } + } + + private static Object wireValue( + com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + if (field.getJavaType() == com.google.protobuf.Descriptors.FieldDescriptor.JavaType.ENUM) { + if (value instanceof String) { + String name = (String) value; + com.google.protobuf.Descriptors.EnumValueDescriptor member = + field.getEnumType().findValueByName(name); + if (member != null) return member; + for (com.google.protobuf.Descriptors.EnumValueDescriptor candidate : + field.getEnumType().getValues()) + if (candidate.getName().endsWith("_" + name)) return candidate; + throw new IllegalArgumentException("Unknown enum value: " + name); + } + if (value instanceof Number) + return field.getEnumType().findValueByNumberCreatingIfUnknown(((Number) value).intValue()); + if (value instanceof com.google.protobuf.ProtocolMessageEnum) + return ((com.google.protobuf.ProtocolMessageEnum) value).getValueDescriptor(); + } + if (value instanceof Number) { + switch (field.getJavaType()) { + case INT: + return ((Number) value).intValue(); + case LONG: + return ((Number) value).longValue(); + case FLOAT: + return ((Number) value).floatValue(); + case DOUBLE: + return ((Number) value).doubleValue(); + default: + break; + } + } + return value; + } + + public static java.util.Map protoMap(Object value) { + java.util.Map result = new java.util.LinkedHashMap<>(); + for (com.google.protobuf.Message entry : (java.util.List) value) + result.put(get(entry, "key"), get(entry, "value")); + return result; + } + + public static java.util.List map( + java.util.List values, java.util.function.Function function) { + java.util.List result = new java.util.ArrayList<>(values.size()); + for (A value : values) result.add(function.apply(value)); + return result; + } + + public static java.util.Map mapValues( + java.util.Map values, + java.util.function.Function key, + java.util.function.Function value) { + java.util.Map result = new java.util.LinkedHashMap<>(); + for (java.util.Map.Entry entry : values.entrySet()) + result.put(key.apply(entry.getKey()), value.apply(entry.getValue())); + return result; + } + + public static final class FunctionReference { + private final F callable; + private final N name; + + private FunctionReference(F callable, N name) { + this.callable = callable; + this.name = name; + } + + public static FunctionReference callable(F value) { + return new FunctionReference<>(java.util.Objects.requireNonNull(value), null); + } + + public static FunctionReference named(N value) { + return new FunctionReference<>(null, java.util.Objects.requireNonNull(value)); + } + + public boolean isNamed() { + return name != null; + } + + public F getCallable() { + return callable; + } + + public N getName() { + return name; + } + } + + public interface Flag { + long getBit(); + } + + public static long flags(java.util.Set> values) { + long result = 0; + for (Enum value : values) result |= ((Flag) value).getBit(); + return result; + } + + public static & Flag> java.util.EnumSet flagsFromNumber( + long bits, Class type) { + java.util.EnumSet result = java.util.EnumSet.noneOf(type); + for (E value : type.getEnumConstants()) if ((bits & value.getBit()) != 0) result.add(value); + return result; + } + + public static Object decode( + Object value, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type type) { + Class raw = + type instanceof Class + ? (Class) type + : type instanceof java.lang.reflect.ParameterizedType + ? (Class) ((java.lang.reflect.ParameterizedType) type).getRawType() + : Object.class; + if (value instanceof io.temporal.api.common.v1.Payload) + return converter.fromPayload((io.temporal.api.common.v1.Payload) value, raw, type); + io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; + return converter.fromPayloads(0, java.util.Optional.of(payloads), raw, type); + } + + public static java.util.List decodeSequence( + Object value, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type element) { + io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; + Class raw = + element instanceof Class + ? (Class) element + : element instanceof java.lang.reflect.ParameterizedType + ? (Class) ((java.lang.reflect.ParameterizedType) element).getRawType() + : Object.class; + java.util.List result = new java.util.ArrayList<>(); + for (io.temporal.api.common.v1.Payload payload : payloads.getPayloadsList()) + result.add(converter.fromPayload(payload, raw, element)); + return result; + } + + @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Result.Deserializer.class) + public static final class Result { + private final boolean ok; + private final Object value; + + private Result(boolean ok, Object value) { + this.ok = ok; + this.value = value; + } + + public static Result ok(O value) { + return new Result<>(true, value); + } + + public static Result err(E value) { + return new Result<>(false, value); + } + + @com.fasterxml.jackson.annotation.JsonIgnore + public boolean isOk() { + return ok; + } + + public String getTag() { + return ok ? "ok" : "err"; + } + + public Object getValue() { + return value; + } + + @com.fasterxml.jackson.annotation.JsonIgnore + public O getOk() { + if (!ok) throw new IllegalStateException("Error result"); + return (O) value; + } + + @com.fasterxml.jackson.annotation.JsonIgnore + public E getErr() { + if (ok) throw new IllegalStateException("Success result"); + return (E) value; + } + + public static final class Deserializer + extends com.fasterxml.jackson.databind.JsonDeserializer + implements com.fasterxml.jackson.databind.deser.ContextualDeserializer { + private final com.fasterxml.jackson.databind.JavaType type; + + public Deserializer() { + this(null); + } + + private Deserializer(com.fasterxml.jackson.databind.JavaType type) { + this.type = type; + } + + public com.fasterxml.jackson.databind.JsonDeserializer createContextual( + com.fasterxml.jackson.databind.DeserializationContext context, + com.fasterxml.jackson.databind.BeanProperty property) { + return new Deserializer(context.getContextualType()); + } + + public Result deserialize( + com.fasterxml.jackson.core.JsonParser parser, + com.fasterxml.jackson.databind.DeserializationContext context) + throws java.io.IOException { + com.fasterxml.jackson.databind.JsonNode node = parser.getCodec().readTree(parser); + String tag = node.get("tag").asText(); + if (!"ok".equals(tag) && !"err".equals(tag)) + throw new java.io.IOException("Unknown result tag: " + tag); + boolean ok = "ok".equals(tag); + Object value = + context.readTreeAsValue(node.get("value"), type.containedTypeOrUnknown(ok ? 0 : 1)); + return new Result(ok, value); + } + } + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowRequest.java new file mode 100644 index 0000000000..856d8215e4 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowRequest.java @@ -0,0 +1,750 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.nexus.system.workflowservice; + +/** Request fields for signaling a workflow, starting it first if needed. */ +@io.temporal.common.converter.TransferTypeConvertible( + SignalWithStartWorkflowRequest.Converter.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SignalWithStartWorkflowRequest { + private final String workflow; + + /** Arguments for the workflow. */ + private final java.util.List args; + + /** Unique identifier for the workflow execution. */ + private final String id; + + /** Task queue to run the workflow on. */ + private final String taskQueue; + + private final String signal; + + /** Arguments for the signal. */ + private final java.util.List signalArgs; + + /** Total workflow execution timeout, including retries and continue-as-new. */ + private final java.time.Duration executionTimeout; + + /** Timeout of a single workflow run. */ + private final java.time.Duration runTimeout; + + /** Timeout of a single workflow task. */ + private final java.time.Duration taskTimeout; + + /** Request ID used to deduplicate workflow start requests. */ + private final String requestId; + + /** Behavior when a closed workflow with the same ID exists. Default is allow-duplicate. */ + private final io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy; + + /** + * Behavior when a workflow is currently running with the same ID. Set to use-existing for + * idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is + * terminate-if-running. + */ + private final io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy; + + /** Retry policy for the workflow. */ + private final io.temporal.common.RetryOptions retryPolicy; + + /** Cron schedule for recurring workflow executions. See https://docs.temporal.io/cron-job. */ + private final String cronSchedule; + + /** Memo for the workflow. */ + private final java.util.Map memo; + + /** Typed search attributes for the workflow. */ + private final io.temporal.common.SearchAttributes searchAttributes; + + /** Priority of the workflow execution. */ + private final io.temporal.common.Priority priority; + + /** Override for workflow versioning behavior. */ + private final io.temporal.common.VersioningOverride versioningOverride; + + /** Amount of time to wait before starting the workflow. This does not work with cron-schedule. */ + private final java.time.Duration startDelay; + + private final io.temporal.nexus.system.workflowservice.UserMetadata userMetadata; + private final String namespace; + private final java.util.Map headers; + + @com.fasterxml.jackson.annotation.JsonCreator + public SignalWithStartWorkflowRequest( + @com.fasterxml.jackson.annotation.JsonProperty("workflow") String workflow, + @com.fasterxml.jackson.annotation.JsonProperty("args") java.util.List args, + @com.fasterxml.jackson.annotation.JsonProperty("id") String id, + @com.fasterxml.jackson.annotation.JsonProperty("taskQueue") String taskQueue, + @com.fasterxml.jackson.annotation.JsonProperty("signal") String signal, + @com.fasterxml.jackson.annotation.JsonProperty("signalArgs") + java.util.List signalArgs, + @com.fasterxml.jackson.annotation.JsonProperty("executionTimeout") + java.time.Duration executionTimeout, + @com.fasterxml.jackson.annotation.JsonProperty("runTimeout") java.time.Duration runTimeout, + @com.fasterxml.jackson.annotation.JsonProperty("taskTimeout") java.time.Duration taskTimeout, + @com.fasterxml.jackson.annotation.JsonProperty("requestId") String requestId, + @com.fasterxml.jackson.annotation.JsonProperty("idReusePolicy") + io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy, + @com.fasterxml.jackson.annotation.JsonProperty("idConflictPolicy") + io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy, + @com.fasterxml.jackson.annotation.JsonProperty("retryPolicy") + io.temporal.common.RetryOptions retryPolicy, + @com.fasterxml.jackson.annotation.JsonProperty("cronSchedule") String cronSchedule, + @com.fasterxml.jackson.annotation.JsonProperty("memo") java.util.Map memo, + @com.fasterxml.jackson.annotation.JsonProperty("searchAttributes") + io.temporal.common.SearchAttributes searchAttributes, + @com.fasterxml.jackson.annotation.JsonProperty("priority") + io.temporal.common.Priority priority, + @com.fasterxml.jackson.annotation.JsonProperty("versioningOverride") + io.temporal.common.VersioningOverride versioningOverride, + @com.fasterxml.jackson.annotation.JsonProperty("startDelay") java.time.Duration startDelay, + @com.fasterxml.jackson.annotation.JsonProperty("userMetadata") + io.temporal.nexus.system.workflowservice.UserMetadata userMetadata, + @com.fasterxml.jackson.annotation.JsonProperty("namespace") String namespace, + @com.fasterxml.jackson.annotation.JsonProperty("headers") + java.util.Map headers) { + this.workflow = workflow; + this.args = args; + this.id = id; + this.taskQueue = taskQueue; + this.signal = signal; + this.signalArgs = signalArgs; + this.executionTimeout = executionTimeout; + this.runTimeout = runTimeout; + this.taskTimeout = taskTimeout; + this.requestId = requestId; + this.idReusePolicy = idReusePolicy; + this.idConflictPolicy = idConflictPolicy; + this.retryPolicy = retryPolicy; + this.cronSchedule = cronSchedule; + this.memo = memo; + this.searchAttributes = searchAttributes; + this.priority = priority; + this.versioningOverride = versioningOverride; + this.startDelay = startDelay; + this.userMetadata = userMetadata; + this.namespace = namespace; + this.headers = headers; + } + + public String getWorkflow() { + return workflow; + } + + public java.util.List getArgs() { + return args; + } + + public String getId() { + return id; + } + + public String getTaskQueue() { + return taskQueue; + } + + public String getSignal() { + return signal; + } + + public java.util.List getSignalArgs() { + return signalArgs; + } + + public java.time.Duration getExecutionTimeout() { + return executionTimeout; + } + + public java.time.Duration getRunTimeout() { + return runTimeout; + } + + public java.time.Duration getTaskTimeout() { + return taskTimeout; + } + + public String getRequestId() { + return requestId; + } + + public io.temporal.api.enums.v1.WorkflowIdReusePolicy getIdReusePolicy() { + return idReusePolicy; + } + + public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getIdConflictPolicy() { + return idConflictPolicy; + } + + public io.temporal.common.RetryOptions getRetryPolicy() { + return retryPolicy; + } + + public String getCronSchedule() { + return cronSchedule; + } + + public java.util.Map getMemo() { + return memo; + } + + public io.temporal.common.SearchAttributes getSearchAttributes() { + return searchAttributes; + } + + public io.temporal.common.Priority getPriority() { + return priority; + } + + public io.temporal.common.VersioningOverride getVersioningOverride() { + return versioningOverride; + } + + public java.time.Duration getStartDelay() { + return startDelay; + } + + public io.temporal.nexus.system.workflowservice.UserMetadata getUserMetadata() { + return userMetadata; + } + + public String getNamespace() { + return namespace; + } + + public java.util.Map getHeaders() { + return headers; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(SignalWithStartWorkflowRequest value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private Builder() {} + + private Builder(SignalWithStartWorkflowRequest value) { + if (value == null) return; + this.workflow = value.workflow; + this.args = value.args; + this.id = value.id; + this.taskQueue = value.taskQueue; + this.signal = value.signal; + this.signalArgs = value.signalArgs; + this.executionTimeout = value.executionTimeout; + this.runTimeout = value.runTimeout; + this.taskTimeout = value.taskTimeout; + this.requestId = value.requestId; + this.idReusePolicy = value.idReusePolicy; + this.idConflictPolicy = value.idConflictPolicy; + this.retryPolicy = value.retryPolicy; + this.cronSchedule = value.cronSchedule; + this.memo = value.memo; + this.searchAttributes = value.searchAttributes; + this.priority = value.priority; + this.versioningOverride = value.versioningOverride; + this.startDelay = value.startDelay; + this.userMetadata = value.userMetadata; + this.namespace = value.namespace; + this.headers = value.headers; + } + + private String workflow = null; + + public Builder setWorkflow(String value) { + this.workflow = value; + return this; + } + + private java.util.List args = null; + + public Builder setArgs(java.util.List value) { + this.args = value; + return this; + } + + private String id = ""; + + public Builder setId(String value) { + this.id = value; + return this; + } + + private String taskQueue = null; + + public Builder setTaskQueue(String value) { + this.taskQueue = value; + return this; + } + + private String signal = ""; + + public Builder setSignal(String value) { + this.signal = value; + return this; + } + + private java.util.List signalArgs = null; + + public Builder setSignalArgs(java.util.List value) { + this.signalArgs = value; + return this; + } + + private java.time.Duration executionTimeout = null; + + public Builder setExecutionTimeout(java.time.Duration value) { + this.executionTimeout = value; + return this; + } + + private java.time.Duration runTimeout = null; + + public Builder setRunTimeout(java.time.Duration value) { + this.runTimeout = value; + return this; + } + + private java.time.Duration taskTimeout = null; + + public Builder setTaskTimeout(java.time.Duration value) { + this.taskTimeout = value; + return this; + } + + private String requestId = null; + + public Builder setRequestId(String value) { + this.requestId = value; + return this; + } + + private io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy = + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(1); + + public Builder setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { + this.idReusePolicy = value; + return this; + } + + private io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy = null; + + public Builder setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { + this.idConflictPolicy = value; + return this; + } + + private io.temporal.common.RetryOptions retryPolicy = null; + + public Builder setRetryPolicy(io.temporal.common.RetryOptions value) { + this.retryPolicy = value; + return this; + } + + private String cronSchedule = null; + + public Builder setCronSchedule(String value) { + this.cronSchedule = value; + return this; + } + + private java.util.Map memo = null; + + public Builder setMemo(java.util.Map value) { + this.memo = value; + return this; + } + + private io.temporal.common.SearchAttributes searchAttributes = null; + + public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { + this.searchAttributes = value; + return this; + } + + private io.temporal.common.Priority priority = null; + + public Builder setPriority(io.temporal.common.Priority value) { + this.priority = value; + return this; + } + + private io.temporal.common.VersioningOverride versioningOverride = null; + + public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { + this.versioningOverride = value; + return this; + } + + private java.time.Duration startDelay = null; + + public Builder setStartDelay(java.time.Duration value) { + this.startDelay = value; + return this; + } + + private io.temporal.nexus.system.workflowservice.UserMetadata userMetadata = null; + + public Builder setUserMetadata(io.temporal.nexus.system.workflowservice.UserMetadata value) { + this.userMetadata = value; + return this; + } + + private String namespace = null; + + public Builder setNamespace(String value) { + this.namespace = value; + return this; + } + + private java.util.Map headers = null; + + public Builder setHeaders(java.util.Map value) { + this.headers = value; + return this; + } + + public Builder setStaticSummary(Object value) { + this.userMetadata = + io.temporal.nexus.system.workflowservice.UserMetadata.newBuilder(this.userMetadata) + .setStaticSummary(value) + .build(); + return this; + } + + public Builder setStaticDetails(Object value) { + this.userMetadata = + io.temporal.nexus.system.workflowservice.UserMetadata.newBuilder(this.userMetadata) + .setStaticDetails(value) + .build(); + return this; + } + + public SignalWithStartWorkflowRequest build() { + return new SignalWithStartWorkflowRequest( + workflow, + args, + id, + taskQueue, + signal, + signalArgs, + executionTimeout, + runTimeout, + taskTimeout, + requestId, + idReusePolicy, + idConflictPolicy, + retryPolicy, + cronSchedule, + memo, + searchAttributes, + priority, + versioningOverride, + startDelay, + userMetadata, + namespace == null + ? io.temporal.internal.nexus.system.TemporalModelConverters.workflowNamespace() + : namespace, + headers); + } + } + + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto( + io.temporal.common.converter.DataConverter converter) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.Builder proto = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder(); + if (this.workflow != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "workflow_type", + io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeToProto( + converter, (this.workflow))); + if (this.args != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "input", + converter + .toPayloads((this.args).toArray()) + .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + if (this.id != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set(proto, "workflow_id", (this.id)); + if (this.taskQueue != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "task_queue", + io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueToProto( + converter, (this.taskQueue))); + if (this.signal != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "signal_name", (this.signal)); + if (this.signalArgs != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "signal_input", + converter + .toPayloads((this.signalArgs).toArray()) + .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + if (this.executionTimeout != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "workflow_execution_timeout", + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.executionTimeout))); + if (this.runTimeout != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "workflow_run_timeout", + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.runTimeout))); + if (this.taskTimeout != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "workflow_task_timeout", + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.taskTimeout))); + if (this.requestId != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "request_id", (this.requestId)); + if (this.idReusePolicy != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "workflow_id_reuse_policy", (this.idReusePolicy).getNumber()); + if (this.idConflictPolicy != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "workflow_id_conflict_policy", (this.idConflictPolicy).getNumber()); + if (this.retryPolicy != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "retry_policy", + io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyToProto( + converter, (this.retryPolicy))); + if (this.cronSchedule != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "cron_schedule", (this.cronSchedule)); + if (this.memo != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "memo", + io.temporal.internal.nexus.system.TemporalModelConverters.memoToProto( + converter, (this.memo))); + if (this.searchAttributes != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "search_attributes", + io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesToProto( + converter, (this.searchAttributes))); + if (this.priority != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "priority", + io.temporal.internal.nexus.system.TemporalModelConverters.priorityToProto( + converter, (this.priority))); + if (this.versioningOverride != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "versioning_override", + io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideToProto( + converter, (this.versioningOverride))); + if (this.startDelay != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "workflow_start_delay", + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.startDelay))); + if (this.userMetadata != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "user_metadata", (this.userMetadata).toProto(converter)); + if (this.namespace != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "namespace", (this.namespace)); + if (this.headers != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, + "header", + io.temporal.internal.nexus.system.TemporalModelConverters.headerToProto( + converter, (this.headers))); + return proto.build(); + } + + public static SignalWithStartWorkflowRequest fromProto( + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { + Builder builder = SignalWithStartWorkflowRequest.newBuilder(); + if (true) + builder.setWorkflow( + io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto( + converter, + (io.temporal.api.common.v1.WorkflowType) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "workflow_type"))); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "input")) + builder.setArgs( + (java.util.List) + (Object) + io.temporal.nexus.system.workflowservice.NexgenRuntime.decodeSequence( + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "input"), + converter, + io.temporal.nexus.system.workflowservice.NexgenRuntime.argument( + new com.fasterxml.jackson.core.type.TypeReference< + java.util.List>() {}.getType(), + 0))); + if (true) + builder.setId( + (String) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "workflow_id")); + if (true) + builder.setTaskQueue( + io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto( + converter, + (io.temporal.api.taskqueue.v1.TaskQueue) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "task_queue"))); + if (true) + builder.setSignal( + (String) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "signal_name")); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "signal_input")) + builder.setSignalArgs( + (java.util.List) + (Object) + io.temporal.nexus.system.workflowservice.NexgenRuntime.decodeSequence( + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "signal_input"), + converter, + io.temporal.nexus.system.workflowservice.NexgenRuntime.argument( + new com.fasterxml.jackson.core.type.TypeReference< + java.util.List>() {}.getType(), + 0))); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has( + proto, "workflow_execution_timeout")) + builder.setExecutionTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, + (com.google.protobuf.Duration) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "workflow_execution_timeout"))); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "workflow_run_timeout")) + builder.setRunTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, + (com.google.protobuf.Duration) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "workflow_run_timeout"))); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "workflow_task_timeout")) + builder.setTaskTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, + (com.google.protobuf.Duration) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "workflow_task_timeout"))); + if (true) + builder.setRequestId( + (String) io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "request_id")); + if (true) + builder.setIdReusePolicy( + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( + ((com.google.protobuf.Descriptors.EnumValueDescriptor) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "workflow_id_reuse_policy")) + .getNumber())); + if (true) + builder.setIdConflictPolicy( + io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber( + ((com.google.protobuf.Descriptors.EnumValueDescriptor) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "workflow_id_conflict_policy")) + .getNumber())); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "retry_policy")) + builder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyFromProto( + converter, + (io.temporal.api.common.v1.RetryPolicy) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "retry_policy"))); + if (true) + builder.setCronSchedule( + (String) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "cron_schedule")); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "memo")) + builder.setMemo( + io.temporal.internal.nexus.system.TemporalModelConverters.memoFromProto( + converter, + (io.temporal.api.common.v1.Memo) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "memo"))); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "search_attributes")) + builder.setSearchAttributes( + io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesFromProto( + converter, + (io.temporal.api.common.v1.SearchAttributes) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "search_attributes"))); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "priority")) + builder.setPriority( + io.temporal.internal.nexus.system.TemporalModelConverters.priorityFromProto( + converter, + (io.temporal.api.common.v1.Priority) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "priority"))); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "versioning_override")) + builder.setVersioningOverride( + io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideFromProto( + converter, + (io.temporal.api.workflow.v1.VersioningOverride) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "versioning_override"))); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "workflow_start_delay")) + builder.setStartDelay( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, + (com.google.protobuf.Duration) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "workflow_start_delay"))); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "user_metadata")) + builder.setUserMetadata( + io.temporal.nexus.system.workflowservice.UserMetadata.fromProto( + (io.temporal.api.sdk.v1.UserMetadata) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "user_metadata"), + converter, + io.temporal.nexus.system.workflowservice.UserMetadata.class)); + if (true) + builder.setNamespace( + (String) io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "namespace")); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "header")) + builder.setHeaders( + io.temporal.internal.nexus.system.TemporalModelConverters.headerFromProto( + converter, + (io.temporal.api.common.v1.Header) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "header"))); + return builder.build(); + } + + public static final class Converter + implements io.temporal.common.converter.TransferTypeConverter< + SignalWithStartWorkflowRequest> { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { + return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.class; + } + + public Object toTransferType(SignalWithStartWorkflowRequest value) { + return value == null + ? null + : value.toProto(io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter()); + } + + public SignalWithStartWorkflowRequest fromTransferType( + Object value, java.lang.reflect.Type valueType) { + return value == null + ? null + : fromProto( + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value, + io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter(), + valueType); + } + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowResponse.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowResponse.java new file mode 100644 index 0000000000..9e25e00d48 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowResponse.java @@ -0,0 +1,139 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.nexus.system.workflowservice; + +@io.temporal.common.converter.TransferTypeConvertible( + SignalWithStartWorkflowResponse.Converter.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SignalWithStartWorkflowResponse { + private final String runId; + private final Boolean started; + private final String firstExecutionRunId; + + @com.fasterxml.jackson.annotation.JsonCreator + public SignalWithStartWorkflowResponse( + @com.fasterxml.jackson.annotation.JsonProperty("runId") String runId, + @com.fasterxml.jackson.annotation.JsonProperty("started") Boolean started, + @com.fasterxml.jackson.annotation.JsonProperty("firstExecutionRunId") + String firstExecutionRunId) { + this.runId = runId; + this.started = started; + this.firstExecutionRunId = firstExecutionRunId; + } + + public String getRunId() { + return runId; + } + + public Boolean getStarted() { + return started; + } + + public String getFirstExecutionRunId() { + return firstExecutionRunId; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(SignalWithStartWorkflowResponse value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private Builder() {} + + private Builder(SignalWithStartWorkflowResponse value) { + if (value == null) return; + this.runId = value.runId; + this.started = value.started; + this.firstExecutionRunId = value.firstExecutionRunId; + } + + private String runId = null; + + public Builder setRunId(String value) { + this.runId = value; + return this; + } + + private Boolean started = null; + + public Builder setStarted(Boolean value) { + this.started = value; + return this; + } + + private String firstExecutionRunId = ""; + + public Builder setFirstExecutionRunId(String value) { + this.firstExecutionRunId = value; + return this; + } + + public SignalWithStartWorkflowResponse build() { + return new SignalWithStartWorkflowResponse(runId, started, firstExecutionRunId); + } + } + + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto( + io.temporal.common.converter.DataConverter converter) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); + if (this.runId != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set(proto, "run_id", (this.runId)); + if (this.started != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set(proto, "started", (this.started)); + if (this.firstExecutionRunId != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "first_execution_run_id", (this.firstExecutionRunId)); + return proto.build(); + } + + public static SignalWithStartWorkflowResponse fromProto( + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { + Builder builder = SignalWithStartWorkflowResponse.newBuilder(); + if (true) + builder.setRunId( + (String) io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "run_id")); + if (true) + builder.setStarted( + (Boolean) io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "started")); + if (true) + builder.setFirstExecutionRunId( + (String) + io.temporal.nexus.system.workflowservice.NexgenRuntime.get( + proto, "first_execution_run_id")); + return builder.build(); + } + + public static final class Converter + implements io.temporal.common.converter.TransferTypeConverter< + SignalWithStartWorkflowResponse> { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { + return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.class; + } + + public Object toTransferType(SignalWithStartWorkflowResponse value) { + return value == null + ? null + : value.toProto(io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter()); + } + + public SignalWithStartWorkflowResponse fromTransferType( + Object value, java.lang.reflect.Type valueType) { + return value == null + ? null + : fromProto( + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value, + io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter(), + valueType); + } + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusOperations.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusOperations.java new file mode 100644 index 0000000000..81bd118d68 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusOperations.java @@ -0,0 +1,40 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.nexus.system.workflowservice; + +/** Generated operation dispatch and serialization context acquisition. */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SystemNexusOperations { + private SystemNexusOperations() {} + + public static + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput< + R> + execute( + SystemNexusWorkflowOutboundInterceptor interceptor, + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + R> + input) { + if ("temporal.api.workflowservice.v1.WorkflowService".equals(input.getService()) + && "SignalWithStartWorkflowExecution".equals(input.getOperation())) + return (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationOutput< + R>) + interceptor.executeSignalWithStartWorkflow( + (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput) + input); + throw new IllegalArgumentException( + "Unsupported system Nexus operation: " + input.getService() + "/" + input.getOperation()); + } + + public static io.temporal.payload.context.SerializationContext serializationContext( + String service, String operation, Object request) { + if ("temporal.api.workflowservice.v1.WorkflowService".equals(service) + && "SignalWithStartWorkflowExecution".equals(operation)) + return io.temporal.internal.nexus.system.TemporalModelConverters + .signalWithStartWorkflowSerializationContext( + (io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest) request); + return null; + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusWorkflowOutboundInterceptor.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusWorkflowOutboundInterceptor.java new file mode 100644 index 0000000000..cfe819438e --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusWorkflowOutboundInterceptor.java @@ -0,0 +1,41 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.nexus.system.workflowservice; + +/** Generated typed system Nexus hooks. */ +public interface SystemNexusWorkflowOutboundInterceptor { + + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput< + R> + executeNexusOperation( + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + R> + input); + + default io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationOutput< + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse> + executeSignalWithStartWorkflow( + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse> + input) { + return executeNexusOperation(input); + } + + abstract class Base implements SystemNexusWorkflowOutboundInterceptor { + protected abstract SystemNexusWorkflowOutboundInterceptor nextSystemNexusInterceptor(); + + @Override + public io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationOutput< + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse> + executeSignalWithStartWorkflow( + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse> + input) { + return nextSystemNexusInterceptor().executeSignalWithStartWorkflow(input); + } + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/UserMetadata.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/UserMetadata.java new file mode 100644 index 0000000000..0257cbf762 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/UserMetadata.java @@ -0,0 +1,132 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.nexus.system.workflowservice; + +@io.temporal.common.converter.TransferTypeConvertible(UserMetadata.Converter.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class UserMetadata { + /** + * Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be + * in single-line Temporal Markdown format. + */ + private final Object staticSummary; + + /** + * General fixed details for the workflow execution that may appear in UI and CLI. This can be in + * Temporal Markdown format and can span multiple lines. This value is fixed on the workflow + * execution and cannot be updated. + */ + private final Object staticDetails; + + @com.fasterxml.jackson.annotation.JsonCreator + public UserMetadata( + @com.fasterxml.jackson.annotation.JsonProperty("staticSummary") Object staticSummary, + @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") Object staticDetails) { + this.staticSummary = staticSummary; + this.staticDetails = staticDetails; + } + + public Object getStaticSummary() { + return staticSummary; + } + + public Object getStaticDetails() { + return staticDetails; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(UserMetadata value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private Builder() {} + + private Builder(UserMetadata value) { + if (value == null) return; + this.staticSummary = value.staticSummary; + this.staticDetails = value.staticDetails; + } + + private Object staticSummary = null; + + public Builder setStaticSummary(Object value) { + this.staticSummary = value; + return this; + } + + private Object staticDetails = null; + + public Builder setStaticDetails(Object value) { + this.staticDetails = value; + return this; + } + + public UserMetadata build() { + return new UserMetadata(staticSummary, staticDetails); + } + } + + public io.temporal.api.sdk.v1.UserMetadata toProto( + io.temporal.common.converter.DataConverter converter) { + io.temporal.api.sdk.v1.UserMetadata.Builder proto = + io.temporal.api.sdk.v1.UserMetadata.newBuilder(); + if (this.staticSummary != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "summary", converter.toPayload((this.staticSummary)).get()); + if (this.staticDetails != null) + io.temporal.nexus.system.workflowservice.NexgenRuntime.set( + proto, "details", converter.toPayload((this.staticDetails)).get()); + return proto.build(); + } + + public static UserMetadata fromProto( + io.temporal.api.sdk.v1.UserMetadata proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { + Builder builder = UserMetadata.newBuilder(); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "summary")) + builder.setStaticSummary( + (Object) + io.temporal.nexus.system.workflowservice.NexgenRuntime.decode( + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "summary"), + converter, + Object.class)); + if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "details")) + builder.setStaticDetails( + (Object) + io.temporal.nexus.system.workflowservice.NexgenRuntime.decode( + io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "details"), + converter, + Object.class)); + return builder.build(); + } + + public static final class Converter + implements io.temporal.common.converter.TransferTypeConverter { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { + return io.temporal.api.sdk.v1.UserMetadata.class; + } + + public Object toTransferType(UserMetadata value) { + return value == null + ? null + : value.toProto(io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter()); + } + + public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueType) { + return value == null + ? null + : fromProto( + (io.temporal.api.sdk.v1.UserMetadata) value, + io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter(), + valueType); + } + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowService.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowService.java new file mode 100644 index 0000000000..5c551ad2ed --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowService.java @@ -0,0 +1,9 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.nexus.system.workflowservice; + +@io.nexusrpc.Service(name = "temporal.api.workflowservice.v1.WorkflowService") +public interface WorkflowService { + @io.nexusrpc.Operation(name = "SignalWithStartWorkflowExecution") + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse signalWithStartWorkflow( + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest request); +} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowServiceOperations.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowServiceOperations.java new file mode 100644 index 0000000000..73cb18141f --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowServiceOperations.java @@ -0,0 +1,38 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.nexus.system.workflowservice; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class WorkflowServiceOperations { + private WorkflowServiceOperations() {} + + public static io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse + signalWithStartWorkflow( + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest request) { + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse result = + (io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse) + io.temporal.workflow.Workflow.newUntypedNexusServiceStub( + "temporal.api.workflowservice.v1.WorkflowService", + io.temporal.workflow.NexusServiceOptions.newBuilder() + .setEndpoint("__temporal_system") + .build()) + .execute( + "SignalWithStartWorkflowExecution", + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse.class, + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse.class, + request); + return result; + } + + public static io.temporal.payload.context.SerializationContext + signalWithStartWorkflowSerializationContext( + io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest request) { + return io.temporal.internal.nexus.system.TemporalModelConverters + .signalWithStartWorkflowSerializationContext(request); + } + + public static T withDataConverter( + io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { + return io.temporal.nexus.system.workflowservice.NexgenRuntime.withDataConverter( + converter, action); + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/system-nexus-roots.txt b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/system-nexus-roots.txt new file mode 100644 index 0000000000..434e51e32a --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/system-nexus-roots.txt @@ -0,0 +1,2 @@ +temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest +temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowOptions.java b/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowOptions.java new file mode 100644 index 0000000000..edaf1495ae --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowOptions.java @@ -0,0 +1,226 @@ +package io.temporal.workflow; + +import io.temporal.client.WorkflowOptions; +import io.temporal.common.Experimental; + +/** Options for signaling an external workflow, starting it if necessary. */ +@Experimental +public final class SignalWithStartWorkflowOptions { + private final WorkflowOptions options; + + private SignalWithStartWorkflowOptions(WorkflowOptions options) { + this.options = options; + } + + public static Builder newBuilder() { + return new Builder(null); + } + + public static Builder newBuilder(SignalWithStartWorkflowOptions options) { + return new Builder(options); + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public String getWorkflowId() { + return options.getWorkflowId(); + } + + public String getTaskQueue() { + return options.getTaskQueue(); + } + + public java.time.Duration getWorkflowExecutionTimeout() { + return options.getWorkflowExecutionTimeout(); + } + + public java.time.Duration getWorkflowRunTimeout() { + return options.getWorkflowRunTimeout(); + } + + public java.time.Duration getWorkflowTaskTimeout() { + return options.getWorkflowTaskTimeout(); + } + + public io.temporal.api.enums.v1.WorkflowIdReusePolicy getWorkflowIdReusePolicy() { + return options.getWorkflowIdReusePolicy(); + } + + public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getWorkflowIdConflictPolicy() { + return options.getWorkflowIdConflictPolicy(); + } + + public io.temporal.common.RetryOptions getRetryOptions() { + return options.getRetryOptions(); + } + + public String getCronSchedule() { + return options.getCronSchedule(); + } + + public java.util.Map getMemo() { + return options.getMemo(); + } + + public io.temporal.common.SearchAttributes getTypedSearchAttributes() { + return options.getTypedSearchAttributes(); + } + + public io.temporal.common.Priority getPriority() { + return options.getPriority(); + } + + public io.temporal.common.VersioningOverride getVersioningOverride() { + return options.getVersioningOverride(); + } + + public java.time.Duration getStartDelay() { + return options.getStartDelay(); + } + + public String getStaticSummary() { + return options.getStaticSummary(); + } + + public String getStaticDetails() { + return options.getStaticDetails(); + } + + public String getRequestId() { + return options.getRequestId(); + } + + public static final class Builder { + private final WorkflowOptions.Builder options; + + private Builder(SignalWithStartWorkflowOptions value) { + options = + value == null ? WorkflowOptions.newBuilder() : WorkflowOptions.newBuilder(value.options); + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setWorkflowId}. */ + public Builder setWorkflowId(String value) { + options.setWorkflowId(value); + return this; + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setTaskQueue}. */ + public Builder setTaskQueue(String value) { + options.setTaskQueue(value); + return this; + } + + /** + * Sets the workflow start option; see {@link + * WorkflowOptions.Builder#setWorkflowExecutionTimeout}. + */ + public Builder setWorkflowExecutionTimeout(java.time.Duration value) { + options.setWorkflowExecutionTimeout(value); + return this; + } + + /** + * Sets the workflow start option; see {@link WorkflowOptions.Builder#setWorkflowRunTimeout}. + */ + public Builder setWorkflowRunTimeout(java.time.Duration value) { + options.setWorkflowRunTimeout(value); + return this; + } + + /** + * Sets the workflow start option; see {@link WorkflowOptions.Builder#setWorkflowTaskTimeout}. + */ + public Builder setWorkflowTaskTimeout(java.time.Duration value) { + options.setWorkflowTaskTimeout(value); + return this; + } + + /** + * Sets the workflow start option; see {@link WorkflowOptions.Builder#setWorkflowIdReusePolicy}. + */ + public Builder setWorkflowIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { + options.setWorkflowIdReusePolicy(value); + return this; + } + + /** + * Sets the workflow start option; see {@link + * WorkflowOptions.Builder#setWorkflowIdConflictPolicy}. + */ + public Builder setWorkflowIdConflictPolicy( + io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { + options.setWorkflowIdConflictPolicy(value); + return this; + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setRetryOptions}. */ + public Builder setRetryOptions(io.temporal.common.RetryOptions value) { + options.setRetryOptions(value); + return this; + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setCronSchedule}. */ + public Builder setCronSchedule(String value) { + options.setCronSchedule(value); + return this; + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setMemo}. */ + public Builder setMemo(java.util.Map value) { + options.setMemo(value); + return this; + } + + /** + * Sets the workflow start option; see {@link WorkflowOptions.Builder#setTypedSearchAttributes}. + */ + public Builder setTypedSearchAttributes(io.temporal.common.SearchAttributes value) { + options.setTypedSearchAttributes(value); + return this; + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setPriority}. */ + public Builder setPriority(io.temporal.common.Priority value) { + options.setPriority(value); + return this; + } + + /** + * Sets the workflow start option; see {@link WorkflowOptions.Builder#setVersioningOverride}. + */ + public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { + options.setVersioningOverride(value); + return this; + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setStartDelay}. */ + public Builder setStartDelay(java.time.Duration value) { + options.setStartDelay(value); + return this; + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setStaticSummary}. */ + public Builder setStaticSummary(String value) { + options.setStaticSummary(value); + return this; + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setStaticDetails}. */ + public Builder setStaticDetails(String value) { + options.setStaticDetails(value); + return this; + } + + /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setRequestId}. */ + public Builder setRequestId(String value) { + options.setRequestId(value); + return this; + } + + public SignalWithStartWorkflowOptions build() { + return new SignalWithStartWorkflowOptions(options.build()); + } + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowStub.java b/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowStub.java new file mode 100644 index 0000000000..2b294e1ae9 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowStub.java @@ -0,0 +1,19 @@ +package io.temporal.workflow; + +import io.temporal.common.Experimental; +import io.temporal.internal.sync.SignalWithStartWorkflowInvocationHandler; + +/** Untyped workflow-side stub for atomic signal-with-start through system Nexus. */ +@Experimental +public interface SignalWithStartWorkflowStub { + static SignalWithStartWorkflowStub fromTyped(Object stub) { + return SignalWithStartWorkflowInvocationHandler.fromTyped(stub); + } + + String getWorkflowType(); + + SignalWithStartWorkflowOptions getOptions(); + + /** Waits for signal delivery/start, then returns a stub for signaling or cancellation. */ + ExternalWorkflowStub signalWithStart(String signalName, Object[] signalArgs, Object... startArgs); +} diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java b/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java index 5f1c1f86f6..3937a85b94 100644 --- a/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java +++ b/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java @@ -56,6 +56,33 @@ public final class Workflow { public static final int DEFAULT_VERSION = WorkflowInternal.DEFAULT_VERSION; + /** Creates a typed stub whose workflow and signal calls can be captured by signalWithStart. */ + @Experimental + public static T newSignalWithStartWorkflowStub( + Class workflowInterface, SignalWithStartWorkflowOptions options) { + return io.temporal.internal.sync.SignalWithStartWorkflowInvocationHandler.newStub( + workflowInterface, options); + } + + /** Creates an untyped stub for signaling a workflow and starting it if necessary. */ + @Experimental + public static SignalWithStartWorkflowStub newUntypedSignalWithStartWorkflowStub( + String workflowType, SignalWithStartWorkflowOptions options) { + return new io.temporal.internal.sync.SignalWithStartWorkflowStubImpl(workflowType, options); + } + + /** + * Captures a workflow call and signal call on target, then sends one atomic system Nexus + * operation. Returns an external stub after signal delivery/start completes. Use Async.function + * for a Promise. + */ + @Experimental + public static T signalWithStart( + T target, Functions.Proc workflowCall, Functions.Proc signalCall) { + return io.temporal.internal.sync.SignalWithStartWorkflowInvocationHandler.signalWithStart( + target, workflowCall, signalCall); + } + /** * Creates client stub to activities that implement given interface. ` * diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md new file mode 100644 index 0000000000..08c2012300 --- /dev/null +++ b/temporal-sdk/src/main/nexus/README.md @@ -0,0 +1,23 @@ +# System Nexus bindings + +The WIT definitions here describe the workflow-facing Java models for the +vendored workflow service. They retain the upstream wire schema and add Java +native type and serialization context annotations. Protobuf descriptors from +`temporal-serviceclient:generateProto` validate the mappings during generation. + +Regenerate with nex-gen 0.2.9 built with its `advanced` feature: + +```sh +./gradlew :temporal-sdk:generateNexusSystemApi \ + -PnexgenBinary=/path/to/nexgen +./gradlew --offline spotlessApply +``` + +Generated Java and `system-nexus-roots.txt` are checked in. The manifest derives +from operation input/output protobuf transfer types. The service client's Java +payload visitor generator consumes it, including payload-free response roots, +without depending on compiled SDK classes. + +`TemporalModelConverters` contains the SDK-owned conversion helpers. The emitted +`NexgenRuntime` contains common generated Java code and is rendered from a Rust +string in nex-gen. Normal Java SDK builds do not require Rust or nex-gen. diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md new file mode 100644 index 0000000000..a69b5e6ed8 --- /dev/null +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -0,0 +1,35 @@ +# Signal with start inside workflows + +Signal with start atomically signals an external workflow, starting it when +necessary. It uses the Temporal system Nexus endpoint and requires a server +that supports that service. + +```java +TargetWorkflow target = Workflow.newSignalWithStartWorkflowStub( + TargetWorkflow.class, + SignalWithStartWorkflowOptions.newBuilder() + .setWorkflowId("target") + .setTaskQueue("target-queue") + .build()); +TargetWorkflow external = Workflow.signalWithStart( + target, + () -> target.run(input), + () -> target.notifySignal(signal)); +``` + +The two lambdas capture exactly one workflow call and one signal call. Both +must use `target`; capture does not start the workflow. The operation waits for +signal delivery/start to complete and returns an external workflow stub for +signaling and cancellation. It does not wait for the target workflow's result. +Use `Async.function(() -> Workflow.signalWithStart(...))` for a `Promise`. + +An untyped equivalent is available through +`Workflow.newUntypedSignalWithStartWorkflowStub`. Options default the task queue +to the caller's queue and generate a deterministic workflow ID when omitted. +The destination namespace is the caller's namespace. Serialization uses that +namespace and the destination workflow ID for nested payloads, codecs, and +failure conversion; the system protobuf envelope remains server-readable. + +Generated outbound interceptor hooks expose the system operation independently +of ordinary Nexus operations. Existing outbound interceptor implementations +remain compatible through default methods and the forwarding base class. diff --git a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit new file mode 100644 index 0000000000..5d7d693107 --- /dev/null +++ b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit @@ -0,0 +1,196 @@ +package nexus:temporal-types@1.0.0; + +interface model { + /// String-shaped placeholder for semantic types that generators reinterpret. + type placeholder = string; + + /// @nexus.proto "temporal.api.common.v1.Payload" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="Object" + /// python="typing.Any" + /// typescript="common.Payload" + /// dotnet="object?" + /// dotnet-to="ProtoExtensions.ToPayload" + /// typescript-import="@temporalio/common" + type payload = placeholder; + + /// @nexus.proto "temporal.api.common.v1.Payloads" + /// typescript-import="@temporalio/proto" + /// @nexus.type dotnet="IReadOnlyCollection" dotnet-to="ProtoExtensions.ToPayloads" + /// java="java.util.List" + type payloads = list; + + /// Callable result annotation for workflow functions. + /// @nexus.type + /// python="collections.abc.Awaitable[WorkflowResult]" + /// typescript="Promise" + /// dotnet="System.Threading.Tasks.Task" + type workflow-result = placeholder; + + /// Receiver/context argument for workflow callable method forms. + /// @nexus.type python="typing.Any" typescript="any" dotnet="object" + type callable-prefix = placeholder; + + /// @nexus.function-args + /// varargs=true + /// param="args" + /// typescript-drop-prefix=true + workflow-call: async func(callable-prefix: callable-prefix, args: payloads) -> workflow-result; + + /// Callable result annotation for signal functions. + /// @nexus.type python="None | collections.abc.Awaitable[None]" typescript="void" dotnet="void" + type signal-result = placeholder; + + /// @nexus.function-args + /// varargs=true + /// param="signal-args" + /// typescript-drop-prefix=true + signal-call: func(callable-prefix: callable-prefix, signal-args: payloads) -> signal-result; + + /// @nexus.proto "temporal.api.common.v1.WorkflowType" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="String" + /// java-from="workflowTypeFromProto" + /// java-to="workflowTypeToProto" + /// python="str" + /// typescript="string" + /// dotnet="string" + /// dotnet-to="ProtoExtensions.ToWorkflowTypeProto" + type workflow-type = placeholder; + + /// @nexus.function + /// primary=true + /// signature="workflow-call" + /// args-field="input" + /// result-type-parameter="WorkflowResult" + /// alternate-type="workflow-type" + /// dotnet-name-extractor="TemporalFunctionNames.WorkflowName" + /// dotnet-call-extractor="TemporalFunctionNames.ExtractCall" + /// @nexus.add-rpc-compatible-with "workflow-type" + type workflow-function = placeholder; + + /// @nexus.function + /// signature="signal-call" + /// args-field="signal-input" + /// alternate-type="string" + /// python-converter="signal_function_to_proto" + /// typescript-name-extractor="signalFunctionName" + /// dotnet-name-extractor="TemporalFunctionNames.SignalName" + /// dotnet-call-extractor="TemporalFunctionNames.ExtractCall" + /// typescript-value-type="workflow.SignalDefinition" + /// typescript-args-type="Value extends workflow.SignalDefinition ? Args : never" + /// typescript-import="@temporalio/workflow" + /// @nexus.add-rpc-compatible-with "string" + type signal-function = placeholder; + + /// @nexus.proto "temporal.api.common.v1.RetryPolicy" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.common.RetryOptions" + /// java-from="retryPolicyFromProto" + /// java-to="retryPolicyToProto" + /// python="temporalio.common.RetryPolicy" + /// typescript="common.RetryPolicy" + /// dotnet="Temporalio.Common.RetryPolicy" + /// typescript-import="@temporalio/common" + type retry-policy = placeholder; + + /// @nexus.proto "temporal.api.taskqueue.v1.TaskQueue" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="String" + /// java-from="taskQueueFromProto" + /// java-to="taskQueueToProto" + /// python="str" + /// typescript="string" + /// dotnet="string" + /// dotnet-to="ProtoExtensions.ToTaskQueueProto" + type task-queue = placeholder; + + /// @nexus.proto "temporal.api.common.v1.Memo" typescript-import="@temporalio/proto" + /// @nexus.type python="collections.abc.Mapping[str, typing.Any]" typescript="Record" dotnet="IReadOnlyDictionary" + /// java="java.util.Map" + /// java-from="memoFromProto" + /// java-to="memoToProto" + type memo = placeholder; + + /// @nexus.proto "temporal.api.common.v1.Header" + /// @nexus.type + /// java="java.util.Map" + /// java-from="headerFromProto" + /// java-to="headerToProto" + type header = placeholder; + + /// @nexus.proto "temporal.api.common.v1.SearchAttributes" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.common.SearchAttributes" + /// java-from="searchAttributesFromProto" + /// java-to="searchAttributesToProto" + /// python="temporalio.common.TypedSearchAttributes" + /// typescript="common.TypedSearchAttributes" + /// dotnet="Temporalio.Common.SearchAttributeCollection" + /// typescript-import="@temporalio/common" + type search-attributes = placeholder; + + /// @nexus.proto "temporal.api.common.v1.Priority" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.common.Priority" + /// java-from="priorityFromProto" + /// java-to="priorityToProto" + /// python="temporalio.common.Priority" + /// typescript="common.Priority" + /// dotnet="Temporalio.Common.Priority" + /// typescript-import="@temporalio/common" + type priority = placeholder; + + /// @nexus.proto "temporal.api.workflow.v1.VersioningOverride" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.common.VersioningOverride" + /// java-from="versioningOverrideFromProto" + /// java-to="versioningOverrideToProto" + /// python="temporalio.common.VersioningOverride" + /// typescript="common.VersioningOverride" + /// dotnet="Temporalio.Common.VersioningOverride" + /// typescript-import="@temporalio/common" + type versioning-override = placeholder; + + /// @nexus.proto "google.protobuf.Duration" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="java.time.Duration" + /// java-from="durationFromProto" + /// java-to="durationToProto" + /// python="datetime.timedelta" + /// typescript="common.Duration" + /// dotnet="System.TimeSpan" + /// typescript-import="@temporalio/common" + type duration = placeholder; + + /// @nexus.proto "temporal.api.enums.v1.WorkflowIdReusePolicy" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.api.enums.v1.WorkflowIdReusePolicy" + /// python="temporalio.common.WorkflowIDReusePolicy" + /// typescript="common.WorkflowIdReusePolicy" + /// dotnet="Temporalio.Api.Enums.V1.WorkflowIdReusePolicy" + /// typescript-import="@temporalio/common" + type workflow-id-reuse-policy = placeholder; + + /// @nexus.proto "temporal.api.enums.v1.WorkflowIdConflictPolicy" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="io.temporal.api.enums.v1.WorkflowIdConflictPolicy" + /// python="temporalio.common.WorkflowIDConflictPolicy" + /// typescript="common.WorkflowIdConflictPolicy" + /// dotnet="Temporalio.Api.Enums.V1.WorkflowIdConflictPolicy" + /// typescript-import="@temporalio/common" + type workflow-id-conflict-policy = placeholder; + + /// @nexus.proto "temporal.api.sdk.v1.UserMetadata" typescript-import="@temporalio/proto" + /// @nexus.flatten-in-api + record user-metadata { + /// @nexus.doc "Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be in single-line Temporal Markdown format." + /// @nexus.proto-field "summary" + /// @nexus.flattened-type python="str" typescript="string" dotnet="string" + static-summary: option, + /// @nexus.doc "General fixed details for the workflow execution that may appear in UI and CLI. This can be in Temporal Markdown format and can span multiple lines. This value is fixed on the workflow execution and cannot be updated." + /// @nexus.proto-field "details" + /// @nexus.flattened-type python="str" typescript="string" dotnet="string" + static-details: option, + } +} diff --git a/temporal-sdk/src/main/nexus/workflow-service.wit b/temporal-sdk/src/main/nexus/workflow-service.wit new file mode 100644 index 0000000000..685498ac58 --- /dev/null +++ b/temporal-sdk/src/main/nexus/workflow-service.wit @@ -0,0 +1,129 @@ +package temporal:nexus@1.0.0; + +world system { + export workflow-service; +} + +/// @nexus.endpoint "__temporal_system" +/// @nexus.service-name "temporal.api.workflowservice.v1.WorkflowService" +/// @nexus.namespace dotnet="Temporalio.Workflows" +/// @nexus.operations-class dotnet="Workflow" +/// @nexus.delay-load-temporalio-workflow +/// @nexus.experimental +interface workflow-service { + use nexus:temporal-types/model@1.0.0.{ + duration, + header, + memo, + payloads, + placeholder, + priority, + retry-policy, + search-attributes, + signal-function, + task-queue, + user-metadata, + versioning-override, + workflow-function, + workflow-id-conflict-policy, + workflow-id-reuse-policy, + }; + + /// @nexus.doc "Request fields for signaling a workflow, starting it first if needed." + /// @nexus.experimental + /// @nexus.proto "temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest" typescript-import="@temporalio/proto" + record signal-with-start-workflow-request { + /// @nexus.doc + /// python="Workflow type name or callable identifying the workflow to start." + /// typescript="Workflow type name or workflow function identifying the workflow to start." + /// dotnet="Workflow type name or workflow expression identifying the workflow to start." + /// @nexus.proto-field "workflow_type" + workflow: workflow-function, + /// @nexus.doc "Unique identifier for the workflow execution." + /// @nexus.proto-field "workflow_id" + id: string, + /// @nexus.doc "Task queue to run the workflow on." + task-queue: task-queue, + /// @nexus.doc + /// python="Signal name or callable to send with the start request." + /// typescript="Signal name or signal definition to send with the start request." + /// dotnet="Signal name or signal expression to send with the start request." + /// @nexus.proto-field "signal_name" + signal: signal-function, + /// @nexus.doc "Total workflow execution timeout, including retries and continue-as-new." + /// @nexus.proto-field "workflow_execution_timeout" + execution-timeout: option, + /// @nexus.doc "Timeout of a single workflow run." + /// @nexus.proto-field "workflow_run_timeout" + run-timeout: option, + /// @nexus.doc "Timeout of a single workflow task." + /// @nexus.proto-field "workflow_task_timeout" + task-timeout: option, + /// @nexus.omit + identity: placeholder, + /// @nexus.doc "Request ID used to deduplicate workflow start requests." + request-id: option, + /// @nexus.doc "Behavior when a closed workflow with the same ID exists. Default is allow-duplicate." + /// @nexus.proto-field "workflow_id_reuse_policy" + /// @nexus.default "allow-duplicate" + id-reuse-policy: workflow-id-reuse-policy, + /// @nexus.doc "Behavior when a workflow is currently running with the same ID. Set to use-existing for idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is terminate-if-running." + /// @nexus.proto-field "workflow_id_conflict_policy" + id-conflict-policy: option, + /// @nexus.doc "Retry policy for the workflow." + retry-policy: option, + /// @nexus.doc "Cron schedule for recurring workflow executions. See https://docs.temporal.io/cron-job." + cron-schedule: option, + /// @nexus.doc "Memo for the workflow." + memo: option, + /// @nexus.doc "Typed search attributes for the workflow." + search-attributes: option, + /// @nexus.doc "Priority of the workflow execution." + priority: option, + /// @nexus.doc "Override for workflow versioning behavior." + versioning-override: option, + /// @nexus.doc "Amount of time to wait before starting the workflow. This does not work with cron-schedule." + /// @nexus.proto-field "workflow_start_delay" + start-delay: option, + user-metadata: option, + /// @nexus.source java="workflowNamespace()" python="workflow_namespace" typescript="workflowNamespace" dotnet="TemporalWorkflowContext.WorkflowNamespace" + namespace: string, + /// @nexus.omit + control: placeholder, + /// @nexus.api-omit + /// @nexus.proto-field "header" + headers: option
, + /// @nexus.omit + links: placeholder, + /// @nexus.omit + time-skipping-config: placeholder, + } + + /// @nexus.experimental + /// @nexus.proto "temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse" typescript-import="@temporalio/proto" + record signal-with-start-workflow-response { + run-id: option, + started: option, + /// @nexus.omit + signal-link: placeholder, + first-execution-run-id: string, + } + + /// @nexus.doc + /// "Signal a workflow, starting it first if needed." + /// returns="A workflow handle to the started workflow." + /// @nexus.output-transform + /// python-type="temporalio.workflow.ExternalWorkflowHandle[WorkflowResult]" + /// python="temporalio.workflow.get_external_workflow_handle(request.id, run_id=result.run_id)" + /// typescript-type="workflow.ExternalWorkflowHandle" + /// typescript="workflow.getExternalWorkflowHandle(request.id, result.runId ?? undefined)" + /// typescript-import="@temporalio/workflow" + /// dotnet-type="Temporalio.Workflows.ExternalWorkflowHandle" + /// dotnet="Temporalio.Workflows.Workflow.GetExternalWorkflowHandle(request.Id, result.RunId)" + /// @nexus.operation name="SignalWithStartWorkflowExecution" + /// @nexus.experimental + /// @nexus.serialization-context java="signalWithStartWorkflowSerializationContext" + signal-with-start-workflow: func( + request: signal-with-start-workflow-request, + ) -> signal-with-start-workflow-response; +} diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java new file mode 100644 index 0000000000..2639bea4a7 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java @@ -0,0 +1,225 @@ +package io.temporal.internal.nexus.system; + +import static org.junit.Assert.*; + +import com.google.protobuf.ByteString; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest; +import io.temporal.common.converter.*; +import io.temporal.internal.payload.visitor.SystemNexusPayloads; +import io.temporal.nexus.system.workflowservice.*; +import io.temporal.payload.codec.PayloadCodec; +import io.temporal.payload.context.SerializationContext; +import io.temporal.payload.context.WorkflowSerializationContext; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.junit.Test; + +public class SystemNexusDataConverterTest { + private static final String SERVICE = "temporal.api.workflowservice.v1.WorkflowService"; + private static final String OPERATION = "SignalWithStartWorkflowExecution"; + + private static SignalWithStartWorkflowRequest request(String id) { + return SignalWithStartWorkflowRequest.newBuilder() + .setNamespace("destination") + .setId(id) + .setWorkflow("Target") + .setTaskQueue("queue") + .setSignal("notify") + .setArgs(Arrays.asList("workflow", 42)) + .setSignalArgs(Collections.singletonList("signal")) + .setMemo(Collections.singletonMap("memo", "value")) + .setHeaders( + Collections.singletonMap( + "trace", DefaultDataConverter.STANDARD_INSTANCE.toPayload("trace-value").get())) + .setUserMetadata(UserMetadata.newBuilder().setStaticSummary("summary").build()) + .build(); + } + + @Test + public void nestedPayloadsUseDestinationContextAndOuterEnvelopeBypassesCodecs() throws Exception { + SignalWithStartWorkflowRequest request = request("target"); + WorkflowSerializationContext context = + (WorkflowSerializationContext) + SystemNexusOperations.serializationContext(SERVICE, OPERATION, request); + assertEquals("destination", context.getNamespace()); + assertEquals("target", context.getWorkflowId()); + DataConverter user = + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, + Collections.singletonList(new ContextCodec(null))) + .withContext(context); + SystemNexusDataConverter converter = new SystemNexusDataConverter(user); + Payload encoded = converter.toPayload(request).get(); + assertTrue(SystemNexusPayloads.isSystemPayload(encoded)); + assertFalse(encoded.getMetadataMap().containsKey("test-context")); + SignalWithStartWorkflowExecutionRequest wire = + SignalWithStartWorkflowExecutionRequest.parseFrom(encoded.getData()); + assertEquals( + "target", wire.getInput().getPayloads(0).getMetadataOrThrow("test-context").toStringUtf8()); + assertEquals( + "target", + wire.getSignalInput().getPayloads(0).getMetadataOrThrow("test-context").toStringUtf8()); + assertEquals( + "target", + wire.getMemo().getFieldsOrThrow("memo").getMetadataOrThrow("test-context").toStringUtf8()); + SignalWithStartWorkflowRequest decoded = + converter.fromPayload( + encoded, SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class); + assertEquals(request.getArgs(), decoded.getArgs()); + assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); + assertEquals(request.getMemo(), decoded.getMemo()); + assertEquals(request.getHeaders(), decoded.getHeaders()); + assertEquals( + "target", + wire.getHeader() + .getFieldsOrThrow("trace") + .getMetadataOrThrow("test-context") + .toStringUtf8()); + assertEquals("summary", decoded.getUserMetadata().getStaticSummary()); + } + + @Test + public void codecsVisitNestedPayloadsInsideRawSystemEnvelopes() { + SignalWithStartWorkflowRequest request = request("target"); + CodecDataConverter user = + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, + Collections.singletonList(new ContextCodec("target"))); + Payload plain = + new SystemNexusDataConverter(DefaultDataConverter.STANDARD_INSTANCE) + .toPayload(request) + .get(); + Payload encoded = user.encode(Collections.singletonList(plain)).get(0); + assertEquals(plain, user.decode(Collections.singletonList(encoded)).get(0)); + } + + @Test + public void responseAndRawValuesRoundTripAndConverterScopesRestore() { + SystemNexusDataConverter converter = + new SystemNexusDataConverter(DefaultDataConverter.STANDARD_INSTANCE); + SignalWithStartWorkflowResponse response = + SignalWithStartWorkflowResponse.newBuilder().setRunId("run").setStarted(true).build(); + Payload encoded = converter.toPayload(response).get(); + assertEquals( + "run", + converter + .fromPayload( + encoded, + SignalWithStartWorkflowResponse.class, + SignalWithStartWorkflowResponse.class) + .getRunId()); + assertSame(encoded, converter.toPayload(new RawValue(encoded)).get()); + DataConverter original = NexgenRuntime.dataConverter(); + assertThrows( + IllegalStateException.class, + () -> + NexgenRuntime.withDataConverter( + converter, + () -> { + throw new IllegalStateException("test"); + })); + assertSame(original, NexgenRuntime.dataConverter()); + } + + @Test + public void operationsRetainIndependentDestinationConverters() { + SignalWithStartWorkflowRequest first = request("first"); + SignalWithStartWorkflowRequest second = request("second"); + DataConverter base = + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, + Collections.singletonList(new ContextCodec(null))); + SystemNexusDataConverter firstConverter = + new SystemNexusDataConverter( + base.withContext( + SystemNexusOperations.serializationContext(SERVICE, OPERATION, first))); + SystemNexusDataConverter secondConverter = + new SystemNexusDataConverter( + base.withContext( + SystemNexusOperations.serializationContext(SERVICE, OPERATION, second))); + Payload firstPayload = firstConverter.toPayload(first).get(); + Payload secondPayload = secondConverter.toPayload(second).get(); + assertEquals( + "second", + secondConverter + .fromPayload( + secondPayload, + SignalWithStartWorkflowRequest.class, + SignalWithStartWorkflowRequest.class) + .getId()); + assertEquals( + "first", + firstConverter + .fromPayload( + firstPayload, + SignalWithStartWorkflowRequest.class, + SignalWithStartWorkflowRequest.class) + .getId()); + assertSame(DefaultDataConverter.STANDARD_INSTANCE, NexgenRuntime.dataConverter()); + } + + @Test + public void failuresAndEncodedAttributesUseTheDestinationConverter() { + DataConverter user = + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, + Collections.singletonList(new ContextCodec(null)), + true) + .withContext(new WorkflowSerializationContext("destination", "target")); + SystemNexusDataConverter converter = new SystemNexusDataConverter(user); + io.temporal.api.failure.v1.Failure failure = + converter.exceptionToFailure( + io.temporal.failure.ApplicationFailure.newFailure("message", "type", "details")); + io.temporal.failure.ApplicationFailure decoded = + (io.temporal.failure.ApplicationFailure) converter.failureToException(failure); + assertEquals("message", decoded.getOriginalMessage()); + assertEquals("details", decoded.getDetails().get(0, String.class)); + } + + private static final class ContextCodec implements PayloadCodec { + private final String id; + + private ContextCodec(String id) { + this.id = id; + } + + @Nonnull + @Override + public PayloadCodec withContext(@Nonnull SerializationContext context) { + assertTrue(context instanceof WorkflowSerializationContext); + return new ContextCodec(((WorkflowSerializationContext) context).getWorkflowId()); + } + + @Nonnull + @Override + public List encode(@Nonnull List values) { + assertNotNull(id); + return values.stream() + .map( + value -> { + assertFalse(SystemNexusPayloads.isSystemPayload(value)); + assertFalse( + "Payload was encoded twice", + value.getMetadataMap().containsKey("test-context")); + return value.toBuilder() + .putMetadata("test-context", ByteString.copyFromUtf8(id)) + .build(); + }) + .collect(Collectors.toList()); + } + + @Nonnull + @Override + public List decode(@Nonnull List values) { + return values.stream() + .map( + value -> { + assertEquals(id, value.getMetadataOrThrow("test-context").toStringUtf8()); + return value.toBuilder().removeMetadata("test-context").build(); + }) + .collect(Collectors.toList()); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStorageRunnerTest.java b/temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStorageRunnerTest.java index 323ef817fe..13ecf06ce3 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStorageRunnerTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/payload/storage/ExternalStorageRunnerTest.java @@ -36,6 +36,34 @@ /** Tests external storage message conversion. */ public class ExternalStorageRunnerTest { + @Test + public void systemEnvelopeOffloadsOnlyNestedPayloads() throws Exception { + TestStorageDriver driver = TestStorageDriver.named("system"); + ExternalStorageRunner transformer = transformer(driver, 0); + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest request = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder() + .setInput(Payloads.newBuilder().addPayloads(payload("workflow"))) + .setSignalInput(Payloads.newBuilder().addPayloads(payload("signal"))) + .setSearchAttributes( + SearchAttributes.newBuilder().putIndexedFields("key", payload("search"))) + .build(); + Payload envelope = io.temporal.internal.payload.visitor.SystemNexusPayloads.pack(request); + Payloads original = Payloads.newBuilder().addPayloads(envelope).build(); + Payloads.Builder builder = original.toBuilder(); + transformer.store(builder, null, null, CancellationToken.none()); + Payload stored = builder.getPayloads(0); + assertTrue(io.temporal.internal.payload.visitor.SystemNexusPayloads.isSystemPayload(stored)); + assertNull(ExternalStorageReferences.tryParseReference(stored)); + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest nested = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.parseFrom( + stored.getData()); + assertNotNull(ExternalStorageReferences.tryParseReference(nested.getInput().getPayloads(0))); + assertNotNull( + ExternalStorageReferences.tryParseReference(nested.getSignalInput().getPayloads(0))); + assertEquals(request.getSearchAttributes(), nested.getSearchAttributes()); + assertEquals(original, transformer.retrieve(builder.build(), CancellationToken.none())); + } + @Test public void storeAndRetrieveRoundTripsOverAMessage() throws Exception { TestStorageDriver driver = TestStorageDriver.named("d1"); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java new file mode 100644 index 0000000000..8d48a3364e --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -0,0 +1,150 @@ +package io.temporal.workflow.nexus; + +import static org.junit.Assert.*; + +import io.temporal.common.interceptors.*; +import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest; +import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse; +import io.temporal.testing.internal.SDKTestWorkflowRule; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.*; +import org.junit.Rule; +import org.junit.Test; + +public class SignalWithStartWorkflowTest { + @Rule + public SDKTestWorkflowRule rule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(CallerImpl.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkerInterceptors( + new WorkerInterceptorBase() { + @Override + public WorkflowInboundCallsInterceptor interceptWorkflow( + WorkflowInboundCallsInterceptor next) { + return new WorkflowInboundCallsInterceptorBase(next) { + @Override + public void init(WorkflowOutboundCallsInterceptor outbound) { + super.init( + new WorkflowOutboundCallsInterceptorBase(outbound) { + @Override + public ExecuteNexusOperationOutput< + SignalWithStartWorkflowResponse> + executeSignalWithStartWorkflow( + ExecuteNexusOperationInput< + SignalWithStartWorkflowResponse> + input) { + SignalWithStartWorkflowRequest request = + (SignalWithStartWorkflowRequest) input.getArg(); + assertEquals("Target", request.getWorkflow()); + assertEquals( + Workflow.getInfo().getNamespace(), + request.getNamespace()); + assertEquals("notify", request.getSignal()); + assertEquals("queue", request.getTaskQueue()); + assertEquals("input", request.getArgs().get(0)); + assertEquals("signal", request.getSignalArgs().get(0)); + return new ExecuteNexusOperationOutput<>( + Workflow.newPromise( + SignalWithStartWorkflowResponse.newBuilder() + .setRunId("run") + .build()), + Workflow.newPromise(() -> java.util.Optional.empty())); + } + }); + } + }; + } + }) + .build()) + .build(); + + @Test + public void typedUntypedAndAsyncCallsReturnExternalStubs() { + assertEquals( + "typed:run,untyped:run,async:run", rule.newWorkflowStubTimeoutOptions(Caller.class).run()); + } + + @WorkflowInterface + public interface Target { + @WorkflowMethod(name = "Target") + String run(String value); + + @SignalMethod(name = "notify") + void notifySignal(String value); + + @QueryMethod + String query(); + } + + @WorkflowInterface + public interface Caller { + @WorkflowMethod + String run(); + } + + public static class CallerImpl implements Caller { + @Override + public String run() { + SignalWithStartWorkflowOptions options = + SignalWithStartWorkflowOptions.newBuilder() + .setWorkflowId("typed") + .setTaskQueue("queue") + .build(); + Target target = Workflow.newSignalWithStartWorkflowStub(Target.class, options); + assertThrows( + IllegalArgumentException.class, + () -> + Workflow.signalWithStart( + target, + () -> { + target.run("input"); + target.run("duplicate"); + }, + () -> target.notifySignal("signal"))); + assertThrows( + IllegalArgumentException.class, + () -> + Workflow.signalWithStart( + target, () -> target.query(), () -> target.notifySignal("signal"))); + Target other = Workflow.newSignalWithStartWorkflowStub(Target.class, options); + assertThrows( + IllegalStateException.class, + () -> + Workflow.signalWithStart( + target, () -> other.run("input"), () -> target.notifySignal("signal"))); + Target external = + Workflow.signalWithStart( + target, () -> target.run("input"), () -> target.notifySignal("signal")); + String typed = + Workflow.getWorkflowExecution(external).get().getWorkflowId() + + ":" + + Workflow.getWorkflowExecution(external).get().getRunId(); + ExternalWorkflowStub untyped = + Workflow.newUntypedSignalWithStartWorkflowStub( + "Target", options.toBuilder().setWorkflowId("untyped").build()) + .signalWithStart("notify", new Object[] {"signal"}, "input"); + Target asyncTarget = + Workflow.newSignalWithStartWorkflowStub( + Target.class, options.toBuilder().setWorkflowId("async").build()); + Target async = + Async.function( + () -> + Workflow.signalWithStart( + asyncTarget, + () -> asyncTarget.run("input"), + () -> asyncTarget.notifySignal("signal"))) + .get(); + return typed + + "," + + untyped.getExecution().getWorkflowId() + + ":" + + untyped.getExecution().getRunId() + + "," + + Workflow.getWorkflowExecution(async).get().getWorkflowId() + + ":" + + Workflow.getWorkflowExecution(async).get().getRunId(); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java new file mode 100644 index 0000000000..2362da34bf --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -0,0 +1,91 @@ +package io.temporal.workflow.nexus; + +import static org.junit.Assert.assertEquals; + +import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; +import io.temporal.testing.CloudTestExclusion.RequiresCloudProvisioning; +import io.temporal.testing.CloudTestExclusionNote; +import io.temporal.testing.WorkflowReplayer; +import io.temporal.testing.internal.SDKTestWorkflowRule; +import io.temporal.workflow.*; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@CloudTestExclusionNote("Requires a server supporting the Temporal system Nexus workflow service.") +@Category(RequiresCloudProvisioning.class) +public class SystemSignalWithStartIntegrationTest { + @Rule + public SDKTestWorkflowRule rule = + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(CallerImpl.class, TargetImpl.class).build(); + + @Before + public void requireSystemService() { + Assume.assumeTrue( + "System Nexus requires a supporting external server", + SDKTestWorkflowRule.useExternalService); + } + + @Test + public void startsThenSignalsTheExistingExecutionAndReplays() throws Exception { + Caller caller = rule.newWorkflowStubTimeoutOptions(Caller.class); + String target = caller.run(); + assertEquals( + "start:first:second", + rule.getWorkflowClient().newUntypedWorkflowStub(target).getResult(String.class)); + String callerId = + io.temporal.client.WorkflowStub.fromTyped(caller).getExecution().getWorkflowId(); + WorkflowReplayer.replayWorkflowExecution(rule.getExecutionHistory(callerId), rule.getWorker()); + } + + @WorkflowInterface + public interface Target { + @WorkflowMethod(name = "SystemSignalTarget") + String run(String initial); + + @SignalMethod + void notifySignal(String value); + } + + public static class TargetImpl implements Target { + private final java.util.List signals = new java.util.ArrayList<>(); + + @Override + public String run(String initial) { + Workflow.await(() -> signals.size() == 2); + return initial + ":" + String.join(":", signals); + } + + @Override + public void notifySignal(String value) { + signals.add(value); + } + } + + @WorkflowInterface + public interface Caller { + @WorkflowMethod + String run(); + } + + public static class CallerImpl implements Caller { + @Override + public String run() { + String id = Workflow.getInfo().getWorkflowId() + "-target"; + SignalWithStartWorkflowOptions options = + SignalWithStartWorkflowOptions.newBuilder() + .setWorkflowId(id) + .setWorkflowIdConflictPolicy( + WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) + .build(); + Target target = Workflow.newSignalWithStartWorkflowStub(Target.class, options); + Workflow.signalWithStart( + target, () -> target.run("start"), () -> target.notifySignal("first")); + Workflow.signalWithStart( + target, () -> target.run("ignored"), () -> target.notifySignal("second")); + return id; + } + } +} diff --git a/temporal-serviceclient/build.gradle b/temporal-serviceclient/build.gradle index ec63fa64bf..3b4fa3b326 100644 --- a/temporal-serviceclient/build.gradle +++ b/temporal-serviceclient/build.gradle @@ -149,15 +149,19 @@ sourceSets { dependencies { payloadGeneratorsImplementation "com.google.protobuf:protobuf-java:$protoVersion" + testImplementation sourceSets.payloadGenerators.output } def generatedPayloadVisitorDir = layout.buildDirectory.dir('generated/payloadvisitor/java') def generatePayloadVisitor = tasks.register('generatePayloadVisitor', JavaExec) { dependsOn 'compilePayloadGeneratorsJava', 'generateProto' + mustRunAfter ':temporal-sdk:generateNexusSystemApi' classpath = sourceSets.payloadGenerators.runtimeClasspath mainClass = 'io.temporal.internal.payload.visitor.gen.PayloadVisitorGenerator' - args apiDescriptorSet.get().asFile.absolutePath, generatedPayloadVisitorDir.get().asFile.absolutePath + def systemRoots = project(':temporal-sdk').file('src/main/java/io/temporal/nexus/system/workflowservice/system-nexus-roots.txt') + args apiDescriptorSet.get().asFile.absolutePath, generatedPayloadVisitorDir.get().asFile.absolutePath, systemRoots.absolutePath + inputs.file(systemRoots) inputs.file(apiDescriptorSet) inputs.files(sourceSets.payloadGenerators.runtimeClasspath) outputs.dir(generatedPayloadVisitorDir) diff --git a/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java new file mode 100644 index 0000000000..9ca978cf68 --- /dev/null +++ b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java @@ -0,0 +1,47 @@ +package io.temporal.internal.payload.visitor; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import io.temporal.api.common.v1.Payload; + +/** Fixed binary protobuf envelopes used by Temporal system Nexus operations. */ +public final class SystemNexusPayloads { + private static final String MARKER = "__temporal_system_payload"; + private static final ByteString TRUE = ByteString.copyFromUtf8("true"); + private static final ByteString ENCODING = ByteString.copyFromUtf8("binary/protobuf"); + + private SystemNexusPayloads() {} + + public static boolean isSystemPayload(Payload payload) { + return TRUE.equals(payload.getMetadataMap().get(MARKER)); + } + + public static Payload pack(Message message) { + return Payload.newBuilder() + .putMetadata(MARKER, TRUE) + .putMetadata("encoding", ENCODING) + .putMetadata( + "messageType", ByteString.copyFromUtf8(message.getDescriptorForType().getFullName())) + .setData(message.toByteString()) + .build(); + } + + public static Message.Builder unpack(Payload payload) { + if (!isSystemPayload(payload) || !ENCODING.equals(payload.getMetadataMap().get("encoding"))) { + throw new VisitorException("Invalid Temporal system payload encoding"); + } + ByteString type = payload.getMetadataMap().get("messageType"); + String name = type == null ? "" : type.toStringUtf8(); + MessageRegistryEntry entry = GeneratedPayloadVisitor.SYSTEM_ROOTS.get(name); + if (entry == null) { + throw new VisitorException("Unknown Temporal system payload: " + name); + } + Message.Builder builder = entry.newBuilder.get(); + try { + return builder.mergeFrom(payload.getData()); + } catch (InvalidProtocolBufferException e) { + throw new VisitorException("Failed to unpack Temporal system payload: " + name, e); + } + } +} diff --git a/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/Traversal.java b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/Traversal.java index ffbdd712ce..570d8bd7c0 100644 --- a/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/Traversal.java +++ b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/Traversal.java @@ -82,7 +82,27 @@ void exit(Object previous) { /** Record a visit of a payload sequence (a {@code Payloads} or {@code repeated Payload}). */ void payloads(List batch, Consumer> writeBack) { + if (batch.stream().anyMatch(SystemNexusPayloads::isSystemPayload)) { + List result = new ArrayList<>(); + // Keep ordinary sequences batched: codecs may change their cardinality. + int start = 0; + for (int i = 0; i < batch.size(); i++) { + if (SystemNexusPayloads.isSystemPayload(batch.get(i))) { + if (start < i) { + payloads(batch.subList(start, i), result::addAll); + } + systemPayload(batch.get(i), result::add); + start = i + 1; + } + } + if (start < batch.size()) { + payloads(batch.subList(start, batch.size()), result::addAll); + } + deferWriteBack(() -> writeBack.accept(result)); + return; + } if (payloadVisitor == null) { + deferWriteBack(() -> writeBack.accept(batch)); return; } LeafJob job = new LeafJob(batch, currentContext, false); @@ -92,6 +112,10 @@ void payloads(List batch, Consumer> writeBack) { /** The visitor must return exactly one payload (checked in {@link #record}). */ void singlePayload(Payload value, Consumer writeBack) { + if (SystemNexusPayloads.isSystemPayload(value)) { + systemPayload(value, writeBack); + return; + } if (payloadVisitor == null) { return; } @@ -100,6 +124,13 @@ void singlePayload(Payload value, Consumer writeBack) { writeBacks.add(() -> writeBack.accept(job.result.get(0))); } + private void systemPayload(Payload value, Consumer writeBack) { + Message.Builder inner = SystemNexusPayloads.unpack(value); + dispatch(inner); + deferWriteBack( + () -> writeBack.accept(value.toBuilder().setData(inner.build().toByteString()).build())); + } + /** Applied after all visits, single-threaded, in walk order. */ void deferWriteBack(Runnable writeBack) { writeBacks.add(writeBack); diff --git a/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/gen/ProtoClosure.java b/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/gen/ProtoClosure.java index 9d71f8e16c..c7597fd6eb 100644 --- a/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/gen/ProtoClosure.java +++ b/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/gen/ProtoClosure.java @@ -48,7 +48,27 @@ public boolean reaches(Descriptor d) { /** Builds the closure and payload-reachability set from the given seed file descriptors. */ public static ProtoClosure of(List seeds) { + return of(seeds, java.util.Collections.emptyList()); + } + + /** + * Adds message roots and their reachable fields without requiring their files to be service + * seeds. + */ + public static ProtoClosure of(List seeds, List roots) { List all = collectMessages(fileClosure(seeds)); + Set seen = new HashSet<>(); + for (Descriptor descriptor : all) seen.add(descriptor.getFullName()); + Deque queue = new ArrayDeque<>(roots); + while (!queue.isEmpty()) { + Descriptor descriptor = queue.remove(); + if (!seen.add(descriptor.getFullName())) continue; + if (!descriptor.getOptions().getMapEntry()) all.add(descriptor); + for (FieldDescriptor field : descriptor.getFields()) { + if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) + queue.add(field.getMessageType()); + } + } return new ProtoClosure(all, computeReachability(all)); } diff --git a/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/visitor/gen/PayloadVisitorGenerator.java b/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/visitor/gen/PayloadVisitorGenerator.java index bbe19c1594..87e807ed0c 100644 --- a/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/visitor/gen/PayloadVisitorGenerator.java +++ b/temporal-serviceclient/src/payloadGenerators/java/io/temporal/internal/payload/visitor/gen/PayloadVisitorGenerator.java @@ -87,29 +87,55 @@ public static void main(String[] args) throws Exception { throw new IllegalArgumentException( "usage: PayloadVisitorGenerator "); } - new PayloadVisitorGenerator().run(Paths.get(args[0]), Paths.get(args[1])); + new PayloadVisitorGenerator() + .run(Paths.get(args[0]), Paths.get(args[1]), args.length > 2 ? Paths.get(args[2]) : null); } private ProtoClosure closure; + private final java.util.Set systemRoots = new java.util.TreeSet<>(); void run(Path descriptorSetFile, Path outputRoot) throws IOException, DescriptorValidationException { + run(descriptorSetFile, outputRoot, null); + } + + void run(Path descriptorSetFile, Path outputRoot, Path systemRootsFile) + throws IOException, DescriptorValidationException { Map files = ProtoDescriptorSets.load(descriptorSetFile); + if (systemRootsFile != null) { + for (String line : Files.readAllLines(systemRootsFile, StandardCharsets.UTF_8)) { + if (!line.trim().isEmpty()) systemRoots.add(line.trim()); + } + } List seeds = Arrays.asList( ProtoDescriptorSets.require(files, WORKFLOW_SERVICE_PROTO), ProtoDescriptorSets.require(files, OPERATOR_SERVICE_PROTO)); - this.closure = ProtoClosure.of(seeds); + Map messages = new TreeMap<>(); + for (FileDescriptor file : files.values()) { + for (Descriptor descriptor : file.getMessageTypes()) indexMessages(descriptor, messages); + } + List roots = new ArrayList<>(); + for (String name : systemRoots) { + Descriptor root = messages.get(name); + if (root == null) throw new IllegalStateException("Unknown system Nexus root: " + name); + roots.add(root); + } + this.closure = ProtoClosure.of(seeds, roots); // Deterministic output order, keyed by descriptor full name. Map emitted = new TreeMap<>(); for (Descriptor d : closure.allMessages) { - if (reaches(d)) { + if (reaches(d) || systemRoots.contains(d.getFullName())) { emitted.put(d.getFullName(), d); } } + for (String root : systemRoots) { + if (!emitted.containsKey(root)) + throw new IllegalStateException("Unknown system Nexus root: " + root); + } String source = emit(emitted); Path dir = outputRoot; @@ -122,6 +148,11 @@ void run(Path descriptorSetFile, Path outputRoot) System.out.println("PayloadVisitorGenerator: wrote " + emitted.size() + " visitors to " + out); } + private static void indexMessages(Descriptor descriptor, Map messages) { + messages.put(descriptor.getFullName(), descriptor); + for (Descriptor nested : descriptor.getNestedTypes()) indexMessages(nested, messages); + } + // --- Reachability + classification --- /** Whether {@code d} can transitively contain a payload; delegates to the shared closure. */ @@ -186,9 +217,22 @@ private String emit(Map emitted) { sb.append("final class ").append(OUTPUT_CLASS).append(" {\n"); sb.append(" private ").append(OUTPUT_CLASS).append("() {}\n\n"); + sb.append(" private static Map buildSystemRoots() {\n"); + sb.append(" Map m = new HashMap<>();\n"); + for (String root : systemRoots) { + sb.append(" m.put(\"") + .append(root) + .append("\", REGISTRY.get(\"") + .append(root) + .append("\"));\n"); + } + sb.append(" return m;\n }\n"); + List list = new ArrayList<>(emitted.values()); sb.append(" static final Map REGISTRY = buildRegistry();\n\n"); + sb.append( + " static final Map SYSTEM_ROOTS = buildSystemRoots();\n"); sb.append(" private static Map buildRegistry() {\n"); sb.append(" Map m = new HashMap<>(") .append(Math.max(16, list.size() * 2)) diff --git a/temporal-serviceclient/src/test/java/io/temporal/internal/payload/gen/ProtoClosureRootTest.java b/temporal-serviceclient/src/test/java/io/temporal/internal/payload/gen/ProtoClosureRootTest.java new file mode 100644 index 0000000000..f5913e59bf --- /dev/null +++ b/temporal-serviceclient/src/test/java/io/temporal/internal/payload/gen/ProtoClosureRootTest.java @@ -0,0 +1,54 @@ +package io.temporal.internal.payload.gen; + +import static org.junit.Assert.*; + +import com.google.protobuf.DescriptorProtos.*; +import com.google.protobuf.Descriptors.*; +import io.temporal.api.common.v1.Payload; +import java.util.Arrays; +import java.util.Collections; +import org.junit.Test; + +public class ProtoClosureRootTest { + @Test + public void explicitRootsDiscoverTheirChildrenWithoutServiceSeeds() throws Exception { + String payloadFile = Payload.getDescriptor().getFile().getName(); + FileDescriptor file = + FileDescriptor.buildFrom( + FileDescriptorProto.newBuilder() + .setName("explicit-roots.proto") + .setPackage("temporal.api.test.v1") + .setSyntax("proto3") + .addDependency(payloadFile) + .addMessageType(DescriptorProto.newBuilder().setName("EmptyResponse")) + .addMessageType( + DescriptorProto.newBuilder() + .setName("Request") + .addField( + FieldDescriptorProto.newBuilder() + .setName("child") + .setNumber(1) + .setType(FieldDescriptorProto.Type.TYPE_MESSAGE) + .setTypeName(".temporal.api.test.v1.Child"))) + .addMessageType( + DescriptorProto.newBuilder() + .setName("Child") + .addField( + FieldDescriptorProto.newBuilder() + .setName("payload") + .setNumber(1) + .setType(FieldDescriptorProto.Type.TYPE_MESSAGE) + .setTypeName(".temporal.api.common.v1.Payload"))) + .build(), + new FileDescriptor[] {Payload.getDescriptor().getFile()}); + Descriptor request = file.findMessageTypeByName("Request"); + Descriptor empty = file.findMessageTypeByName("EmptyResponse"); + Descriptor child = file.findMessageTypeByName("Child"); + ProtoClosure closure = ProtoClosure.of(Collections.emptyList(), Arrays.asList(request, empty)); + assertTrue(closure.allMessages.contains(empty)); + assertTrue(closure.allMessages.contains(child)); + assertTrue(closure.reaches(request)); + assertTrue(closure.reaches(child)); + assertFalse(closure.reaches(empty)); + } +} diff --git a/temporal-serviceclient/src/test/java/io/temporal/internal/payload/visitor/SystemNexusPayloadTest.java b/temporal-serviceclient/src/test/java/io/temporal/internal/payload/visitor/SystemNexusPayloadTest.java new file mode 100644 index 0000000000..92def6ebc1 --- /dev/null +++ b/temporal-serviceclient/src/test/java/io/temporal/internal/payload/visitor/SystemNexusPayloadTest.java @@ -0,0 +1,96 @@ +package io.temporal.internal.payload.visitor; + +import static org.junit.Assert.*; + +import com.google.protobuf.ByteString; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.common.v1.Payloads; +import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest; +import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import org.junit.Test; + +public class SystemNexusPayloadTest { + private static Payload payload(String value) { + return Payload.newBuilder().setData(ByteString.copyFromUtf8(value)).build(); + } + + @Test + public void visitsNestedSequencesBeforeRepacking() throws Exception { + SignalWithStartWorkflowExecutionRequest request = + SignalWithStartWorkflowExecutionRequest.newBuilder() + .setInput(Payloads.newBuilder().addPayloads(payload("workflow"))) + .setSignalInput(Payloads.newBuilder().addPayloads(payload("signal"))) + .build(); + CompletableFuture> workflow = new CompletableFuture<>(); + Payloads outer = Payloads.newBuilder().addPayloads(SystemNexusPayloads.pack(request)).build(); + CompletableFuture result = + PayloadVisitors.visit( + outer, + PayloadVisitorOptions.newBuilder( + (context, values) -> { + if (values.get(0).getData().toStringUtf8().equals("workflow")) { + return workflow; + } + return CompletableFuture.completedFuture( + Collections.singletonList(payload("SIGNAL"))); + }) + .build()); + assertFalse(result.isDone()); + workflow.complete(Arrays.asList(payload("ONE"), payload("TWO"))); + SignalWithStartWorkflowExecutionRequest decoded = + SignalWithStartWorkflowExecutionRequest.parseFrom(result.join().getPayloads(0).getData()); + assertEquals(2, decoded.getInput().getPayloadsCount()); + assertEquals("SIGNAL", decoded.getSignalInput().getPayloads(0).getData().toStringUtf8()); + assertEquals( + outer.getPayloads(0).getMetadataMap(), result.join().getPayloads(0).getMetadataMap()); + } + + @Test + public void handlesPayloadFreeResponses() { + Payload response = + SystemNexusPayloads.pack( + SignalWithStartWorkflowExecutionResponse.newBuilder().setRunId("run").build()); + Payloads outer = Payloads.newBuilder().addPayloads(response).build(); + assertEquals( + outer, + PayloadVisitors.visit( + outer, + PayloadVisitorOptions.newBuilder( + (context, values) -> { + throw new AssertionError("Outer envelope was visited"); + }) + .build()) + .join()); + } + + @Test + public void rejectsUnknownAndMalformedMarkedPayloads() { + Payload unknown = + SystemNexusPayloads.pack(SignalWithStartWorkflowExecutionRequest.getDefaultInstance()) + .toBuilder() + .putMetadata("messageType", ByteString.copyFromUtf8("unknown.Message")) + .build(); + Payload malformed = + SystemNexusPayloads.pack(SignalWithStartWorkflowExecutionRequest.getDefaultInstance()) + .toBuilder() + .setData(ByteString.copyFrom(new byte[] {(byte) 0xff})) + .build(); + for (Payload value : Arrays.asList(unknown, malformed)) { + CompletionException error = + assertThrows( + CompletionException.class, + () -> + PayloadVisitors.visit( + Payloads.newBuilder().addPayloads(value).build(), + PayloadVisitorOptions.newBuilder( + (context, values) -> CompletableFuture.completedFuture(values)) + .build()) + .join()); + assertTrue(error.getCause() instanceof VisitorException); + } + } +} From 2764d38718ef296498ae29be49541eb531a3eb8a Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Mon, 19 Oct 2026 12:33:51 -0700 Subject: [PATCH 02/17] Document workflow signal-with-start APIs in changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a35074873..eae65be203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,11 +20,18 @@ to docs, or any other relevant information. ## [Unreleased] ### :boom: Breaking Changes +- `WorkflowOutboundCallsInterceptor` now includes generated system Nexus operation hooks. + Direct implementations must implement the hooks; extending `WorkflowOutboundCallsInterceptorBase` + provides forwarding implementations. - `WorkflowOutboundCallsInterceptor` has new `sleep(Duration, TimerOptions)` and `await(Duration, TimerOptions, String, Supplier)` methods. Implementations that don't extend `WorkflowOutboundCallsInterceptorBase` need to add them, and Base subclasses override them to see calls with options. ### Added +- Workflows can signal with start through the system workflow service using + `Workflow.newSignalWithStartWorkflowStub`, `Workflow.signalWithStart`, or the untyped equivalent. + System Nexus envelopes preserve destination workflow serialization context for nested payloads, + codecs, and external payload storage. Requires a server supporting the system workflow service. - Applications can use the experimental `@TransferTypeConvertible` annotation and `TransferTypeConverter` interface to convert top-level model values to transfer types. The SDK applies this conversion to workflow, activity, Nexus, and schedule payloads, including failure From 7e02a646eea7c65c6fe15005ea0c6739d24a4268 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Mon, 19 Oct 2026 12:56:58 -0700 Subject: [PATCH 03/17] Expose generated system APIs directly through Workflow --- CHANGELOG.md | 3 +- temporal-sdk/build.gradle | 7 +- .../io/temporal/workflow/NexgenRuntime.java | 149 ++++ .../SignalWithStartWorkflowRequest.java | 259 ++++++ .../SignalWithStartWorkflowResponse.java | 57 ++ .../workflow/SystemNexusOperations.java | 16 + ...ystemNexusWorkflowOutboundInterceptor.java | 12 + .../io/temporal/workflow/UserMetadata.java | 58 ++ .../temporal/workflow/WorkflowOperations.java | 13 + .../io/temporal/workflow/WorkflowService.java | 8 + .../temporal/workflow}/system-nexus-roots.txt | 0 .../WorkflowOutboundCallsInterceptor.java | 2 +- .../WorkflowOutboundCallsInterceptorBase.java | 2 +- .../system/SystemNexusDataConverter.java | 2 +- .../nexus/system/TemporalModelConverters.java | 2 +- .../internal/sync/NexusServiceStubImpl.java | 3 +- ...nalWithStartWorkflowInvocationHandler.java | 145 ---- .../sync/SignalWithStartWorkflowStubImpl.java | 96 --- .../internal/sync/SyncWorkflowContext.java | 2 +- .../system/workflowservice/NexgenRuntime.java | 306 ------- .../SignalWithStartWorkflowRequest.java | 750 ------------------ .../SignalWithStartWorkflowResponse.java | 139 ---- .../SystemNexusOperations.java | 40 - ...ystemNexusWorkflowOutboundInterceptor.java | 41 - .../system/workflowservice/UserMetadata.java | 132 --- .../workflowservice/WorkflowService.java | 9 - .../WorkflowServiceOperations.java | 38 - .../SignalWithStartWorkflowOptions.java | 226 ------ .../workflow/SignalWithStartWorkflowStub.java | 19 - .../java/io/temporal/workflow/Workflow.java | 29 +- temporal-sdk/src/main/nexus/README.md | 7 +- .../src/main/nexus/SIGNAL_WITH_START.md | 49 +- .../src/main/nexus/workflow-service.wit | 8 +- .../system/SystemNexusDataConverterTest.java | 26 +- .../nexus/SignalWithStartWorkflowTest.java | 86 +- .../SystemSignalWithStartIntegrationTest.java | 27 +- temporal-serviceclient/build.gradle | 2 +- .../payload/visitor/SystemNexusPayloads.java | 4 +- 38 files changed, 685 insertions(+), 2089 deletions(-) create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java rename temporal-sdk/src/main/{java/io/temporal/nexus/system/workflowservice => generated/io/temporal/workflow}/system-nexus-roots.txt (100%) delete mode 100644 temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowInvocationHandler.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowStubImpl.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/NexgenRuntime.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowRequest.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowResponse.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusOperations.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusWorkflowOutboundInterceptor.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/UserMetadata.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowService.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowServiceOperations.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowOptions.java delete mode 100644 temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowStub.java diff --git a/CHANGELOG.md b/CHANGELOG.md index eae65be203..f3e5554dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,8 @@ to docs, or any other relevant information. ### Added - Workflows can signal with start through the system workflow service using - `Workflow.newSignalWithStartWorkflowStub`, `Workflow.signalWithStart`, or the untyped equivalent. + generated `Workflow.signalWithStartWorkflow(SignalWithStartWorkflowRequest)` API. + Request builders and operations are generated into `io.temporal.workflow`. System Nexus envelopes preserve destination workflow serialization context for nested payloads, codecs, and external payload storage. Requires a server supporting the system workflow service. - Applications can use the experimental `@TransferTypeConvertible` annotation and diff --git a/temporal-sdk/build.gradle b/temporal-sdk/build.gradle index 49e378ad6b..317deaad8d 100644 --- a/temporal-sdk/build.gradle +++ b/temporal-sdk/build.gradle @@ -42,6 +42,7 @@ dependencies { // we need to compile the code with Java 21 and package it in a multi-release jar. // Similarly, Jackson 3 support requires Java 17+ and is compiled separately. sourceSets { + main.java.srcDir 'src/main/generated' java17 { java { srcDirs = ['src/main/java17'] @@ -338,8 +339,8 @@ tasks.named('check') { // Explicit regeneration keeps normal SDK builds independent of the Rust toolchain. // Use -PnexgenBinary=/path/to/nexgen to test an unreleased generator. -def nexusGeneratedDir = layout.buildDirectory.dir('generated/nexus/workflowservice').get().asFile -def nexusCheckedInDir = file('src/main/java/io/temporal/nexus/system/workflowservice') +def nexusGeneratedDir = layout.buildDirectory.dir('generated/nexus/workflow').get().asFile +def nexusCheckedInDir = file('src/main/generated/io/temporal/workflow') tasks.register('generateNexusSystemApi', Exec) { dependsOn ':temporal-serviceclient:generateProto' def binary = providers.gradleProperty('nexgenBinary').orElse('nexgen') @@ -351,7 +352,7 @@ tasks.register('generateNexusSystemApi', Exec) { commandLine binary.get(), 'java', file('src/main/nexus/workflow-service.wit'), file('src/main/nexus/deps'), '--native-api', '--system-nexus', '--support-package', 'io.temporal.internal.nexus.system.TemporalModelConverters', - '--package-name', 'io.temporal.nexus.system.workflowservice', + '--package-name', 'io.temporal.workflow', '--descriptors', project(':temporal-serviceclient').layout.buildDirectory.file('generated/descriptors/temporal-api.desc').get().asFile, '--output', nexusGeneratedDir doFirst { diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java new file mode 100644 index 0000000000..85659e4c73 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java @@ -0,0 +1,149 @@ +// Generated by nexgen. DO NOT EDIT! +package io.temporal.workflow; +/** Shared conversion helpers for generated WIT models. */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class NexgenRuntime { + private NexgenRuntime() {} + private static final ThreadLocal CONVERTER = new ThreadLocal<>(); + public static io.temporal.common.converter.DataConverter dataConverter() { + io.temporal.common.converter.DataConverter value = CONVERTER.get(); + return value == null ? io.temporal.common.converter.DefaultDataConverter.STANDARD_INSTANCE : value; + } + public static T withDataConverter(io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { + io.temporal.common.converter.DataConverter previous = CONVERTER.get(); + CONVERTER.set(converter); + try { return action.get(); } + finally { if (previous == null) CONVERTER.remove(); else CONVERTER.set(previous); } + } + public static java.lang.reflect.Type parameterized(final Class raw, final java.lang.reflect.Type... arguments) { + return new java.lang.reflect.ParameterizedType() { + public java.lang.reflect.Type getRawType() { return raw; } + public java.lang.reflect.Type getOwnerType() { return raw.getDeclaringClass(); } + public java.lang.reflect.Type[] getActualTypeArguments() { return arguments.clone(); } + }; + } + public static java.lang.reflect.Type argument(java.lang.reflect.Type type, int index) { + return type instanceof java.lang.reflect.ParameterizedType ? ((java.lang.reflect.ParameterizedType) type).getActualTypeArguments()[index] : Object.class; + } + public static Object get(com.google.protobuf.Message message, String name) { return message.getField(field(message, name)); } + public static boolean has(com.google.protobuf.Message message, String name) { + com.google.protobuf.Descriptors.FieldDescriptor field = field(message, name); + return field.isRepeated() ? message.getRepeatedFieldCount(field) > 0 : message.hasField(field); + } + private static com.google.protobuf.Descriptors.FieldDescriptor field(com.google.protobuf.MessageOrBuilder message, String name) { + com.google.protobuf.Descriptors.FieldDescriptor field = message.getDescriptorForType().findFieldByName(name); + if (field == null) throw new IllegalArgumentException("Unknown protobuf field: " + name); + return field; + } + public static void set(com.google.protobuf.Message.Builder builder, String name, Object value) { + com.google.protobuf.Descriptors.FieldDescriptor field = field(builder, name); + if (field.isMapField() && value instanceof java.util.Map) { + for (Object raw : ((java.util.Map) value).entrySet()) { + java.util.Map.Entry entry = (java.util.Map.Entry) raw; + com.google.protobuf.Message.Builder entryBuilder = builder.newBuilderForField(field); + set(entryBuilder, "key", entry.getKey()); set(entryBuilder, "value", entry.getValue()); + builder.addRepeatedField(field, entryBuilder.build()); + } + } else if (field.isRepeated()) { + java.util.List normalized = new java.util.ArrayList<>(); + for (Object item : (java.util.List) value) normalized.add(wireValue(field, item)); + builder.setField(field, normalized); + } else { + builder.setField(field, wireValue(field, value)); + } + } + private static Object wireValue(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + if (field.getJavaType() == com.google.protobuf.Descriptors.FieldDescriptor.JavaType.ENUM) { + if (value instanceof String) { + String name = (String) value; + com.google.protobuf.Descriptors.EnumValueDescriptor member = field.getEnumType().findValueByName(name); + if (member != null) return member; + for (com.google.protobuf.Descriptors.EnumValueDescriptor candidate : field.getEnumType().getValues()) if (candidate.getName().endsWith("_" + name)) return candidate; + throw new IllegalArgumentException("Unknown enum value: " + name); + } + if (value instanceof Number) return field.getEnumType().findValueByNumberCreatingIfUnknown(((Number) value).intValue()); + if (value instanceof com.google.protobuf.ProtocolMessageEnum) return ((com.google.protobuf.ProtocolMessageEnum) value).getValueDescriptor(); + } + if (value instanceof Number) { + switch (field.getJavaType()) { + case INT: return ((Number) value).intValue(); + case LONG: return ((Number) value).longValue(); + case FLOAT: return ((Number) value).floatValue(); + case DOUBLE: return ((Number) value).doubleValue(); + default: break; + } + } + return value; + } + public static java.util.Map protoMap(Object value) { + java.util.Map result = new java.util.LinkedHashMap<>(); + for (com.google.protobuf.Message entry : (java.util.List) value) result.put(get(entry, "key"), get(entry, "value")); + return result; + } + public static java.util.List map(java.util.List values, java.util.function.Function function) { + java.util.List result = new java.util.ArrayList<>(values.size()); + for (A value : values) result.add(function.apply(value)); return result; + } + public static java.util.Map mapValues(java.util.Map values, java.util.function.Function key, java.util.function.Function value) { + java.util.Map result = new java.util.LinkedHashMap<>(); + for (java.util.Map.Entry entry : values.entrySet()) result.put(key.apply(entry.getKey()), value.apply(entry.getValue())); return result; + } + public static final class FunctionReference { + private final F callable; private final N name; + private FunctionReference(F callable, N name) { this.callable = callable; this.name = name; } + public static FunctionReference callable(F value) { return new FunctionReference<>(java.util.Objects.requireNonNull(value), null); } + public static FunctionReference named(N value) { return new FunctionReference<>(null, java.util.Objects.requireNonNull(value)); } + public boolean isNamed() { return name != null; } + public F getCallable() { return callable; } + public N getName() { return name; } + } + public interface Flag { long getBit(); } + public static long flags(java.util.Set> values) { long result = 0; for (Enum value : values) result |= ((Flag) value).getBit(); return result; } + public static & Flag> java.util.EnumSet flagsFromNumber(long bits, Class type) { + java.util.EnumSet result = java.util.EnumSet.noneOf(type); + for (E value : type.getEnumConstants()) if ((bits & value.getBit()) != 0) result.add(value); + return result; + } + public static Object decode(Object value, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type type) { + Class raw = type instanceof Class ? (Class) type : type instanceof java.lang.reflect.ParameterizedType ? (Class) ((java.lang.reflect.ParameterizedType) type).getRawType() : Object.class; + if (value instanceof io.temporal.api.common.v1.Payload) return converter.fromPayload((io.temporal.api.common.v1.Payload) value, raw, type); + io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; + return converter.fromPayloads(0, java.util.Optional.of(payloads), raw, type); + } + public static java.util.List decodeSequence(Object value, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type element) { + io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; + Class raw = element instanceof Class ? (Class) element : element instanceof java.lang.reflect.ParameterizedType ? (Class) ((java.lang.reflect.ParameterizedType) element).getRawType() : Object.class; + java.util.List result = new java.util.ArrayList<>(); + for (io.temporal.api.common.v1.Payload payload : payloads.getPayloadsList()) result.add(converter.fromPayload(payload, raw, element)); + return result; + } + @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Result.Deserializer.class) + public static final class Result { + private final boolean ok; private final Object value; + private Result(boolean ok, Object value) { this.ok = ok; this.value = value; } + public static Result ok(O value) { return new Result<>(true, value); } + public static Result err(E value) { return new Result<>(false, value); } + @com.fasterxml.jackson.annotation.JsonIgnore + public boolean isOk() { return ok; } + public String getTag() { return ok ? "ok" : "err"; } + public Object getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonIgnore + public O getOk() { if (!ok) throw new IllegalStateException("Error result"); return (O) value; } + @com.fasterxml.jackson.annotation.JsonIgnore + public E getErr() { if (ok) throw new IllegalStateException("Success result"); return (E) value; } + public static final class Deserializer extends com.fasterxml.jackson.databind.JsonDeserializer implements com.fasterxml.jackson.databind.deser.ContextualDeserializer { + private final com.fasterxml.jackson.databind.JavaType type; + public Deserializer() { this(null); } + private Deserializer(com.fasterxml.jackson.databind.JavaType type) { this.type = type; } + public com.fasterxml.jackson.databind.JsonDeserializer createContextual(com.fasterxml.jackson.databind.DeserializationContext context, com.fasterxml.jackson.databind.BeanProperty property) { return new Deserializer(context.getContextualType()); } + public Result deserialize(com.fasterxml.jackson.core.JsonParser parser, com.fasterxml.jackson.databind.DeserializationContext context) throws java.io.IOException { + com.fasterxml.jackson.databind.JsonNode node = parser.getCodec().readTree(parser); + String tag = node.get("tag").asText(); + if (!"ok".equals(tag) && !"err".equals(tag)) throw new java.io.IOException("Unknown result tag: " + tag); + boolean ok = "ok".equals(tag); + Object value = context.readTreeAsValue(node.get("value"), type.containedTypeOrUnknown(ok ? 0 : 1)); + return new Result(ok, value); + } + } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java new file mode 100644 index 0000000000..179a2ef2c1 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java @@ -0,0 +1,259 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** + * Request fields for signaling a workflow, starting it first if needed. + */ +@io.temporal.common.converter.TransferTypeConvertible(SignalWithStartWorkflowRequest.Converter.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SignalWithStartWorkflowRequest { + private final String workflow; + /** + * Arguments for the workflow. + */ + private final java.util.List args; + /** + * Unique identifier for the workflow execution. + */ + private final String id; + /** + * Task queue to run the workflow on. + */ + private final String taskQueue; + private final String signal; + /** + * Arguments for the signal. + */ + private final java.util.List signalArgs; + /** + * Total workflow execution timeout, including retries and continue-as-new. + */ + private final java.time.Duration executionTimeout; + /** + * Timeout of a single workflow run. + */ + private final java.time.Duration runTimeout; + /** + * Timeout of a single workflow task. + */ + private final java.time.Duration taskTimeout; + /** + * Behavior when a closed workflow with the same ID exists. Default is + * allow-duplicate. + */ + private final io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy; + /** + * Behavior when a workflow is currently running with the same ID. Set to use-existing + * for idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is + * terminate-if-running. + */ + private final io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy; + /** + * Retry policy for the workflow. + */ + private final io.temporal.common.RetryOptions retryPolicy; + /** + * Cron schedule for recurring workflow executions. See + * https://docs.temporal.io/cron-job. + */ + private final String cronSchedule; + /** + * Memo for the workflow. + */ + private final java.util.Map memo; + /** + * Typed search attributes for the workflow. + */ + private final io.temporal.common.SearchAttributes searchAttributes; + /** + * Priority of the workflow execution. + */ + private final io.temporal.common.Priority priority; + /** + * Override for workflow versioning behavior. + */ + private final io.temporal.common.VersioningOverride versioningOverride; + /** + * Amount of time to wait before starting the workflow. This does not work with + * cron-schedule. + */ + private final java.time.Duration startDelay; + private final io.temporal.workflow.UserMetadata userMetadata; + private final String namespace; + private final java.util.Map headers; + @com.fasterxml.jackson.annotation.JsonCreator + public SignalWithStartWorkflowRequest(@com.fasterxml.jackson.annotation.JsonProperty("workflow") String workflow, @com.fasterxml.jackson.annotation.JsonProperty("args") java.util.List args, @com.fasterxml.jackson.annotation.JsonProperty("id") String id, @com.fasterxml.jackson.annotation.JsonProperty("taskQueue") String taskQueue, @com.fasterxml.jackson.annotation.JsonProperty("signal") String signal, @com.fasterxml.jackson.annotation.JsonProperty("signalArgs") java.util.List signalArgs, @com.fasterxml.jackson.annotation.JsonProperty("executionTimeout") java.time.Duration executionTimeout, @com.fasterxml.jackson.annotation.JsonProperty("runTimeout") java.time.Duration runTimeout, @com.fasterxml.jackson.annotation.JsonProperty("taskTimeout") java.time.Duration taskTimeout, @com.fasterxml.jackson.annotation.JsonProperty("idReusePolicy") io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy, @com.fasterxml.jackson.annotation.JsonProperty("idConflictPolicy") io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy, @com.fasterxml.jackson.annotation.JsonProperty("retryPolicy") io.temporal.common.RetryOptions retryPolicy, @com.fasterxml.jackson.annotation.JsonProperty("cronSchedule") String cronSchedule, @com.fasterxml.jackson.annotation.JsonProperty("memo") java.util.Map memo, @com.fasterxml.jackson.annotation.JsonProperty("searchAttributes") io.temporal.common.SearchAttributes searchAttributes, @com.fasterxml.jackson.annotation.JsonProperty("priority") io.temporal.common.Priority priority, @com.fasterxml.jackson.annotation.JsonProperty("versioningOverride") io.temporal.common.VersioningOverride versioningOverride, @com.fasterxml.jackson.annotation.JsonProperty("startDelay") java.time.Duration startDelay, @com.fasterxml.jackson.annotation.JsonProperty("userMetadata") io.temporal.workflow.UserMetadata userMetadata, @com.fasterxml.jackson.annotation.JsonProperty("namespace") String namespace, @com.fasterxml.jackson.annotation.JsonProperty("headers") java.util.Map headers) { + this.workflow = workflow; + this.args = args; + this.id = id; + this.taskQueue = taskQueue; + this.signal = signal; + this.signalArgs = signalArgs; + this.executionTimeout = executionTimeout; + this.runTimeout = runTimeout; + this.taskTimeout = taskTimeout; + this.idReusePolicy = idReusePolicy; + this.idConflictPolicy = idConflictPolicy; + this.retryPolicy = retryPolicy; + this.cronSchedule = cronSchedule; + this.memo = memo; + this.searchAttributes = searchAttributes; + this.priority = priority; + this.versioningOverride = versioningOverride; + this.startDelay = startDelay; + this.userMetadata = userMetadata; + this.namespace = namespace; + this.headers = headers; + } + public String getWorkflow() { return workflow; } + public java.util.List getArgs() { return args; } + public String getId() { return id; } + public String getTaskQueue() { return taskQueue; } + public String getSignal() { return signal; } + public java.util.List getSignalArgs() { return signalArgs; } + public java.time.Duration getExecutionTimeout() { return executionTimeout; } + public java.time.Duration getRunTimeout() { return runTimeout; } + public java.time.Duration getTaskTimeout() { return taskTimeout; } + public io.temporal.api.enums.v1.WorkflowIdReusePolicy getIdReusePolicy() { return idReusePolicy; } + public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getIdConflictPolicy() { return idConflictPolicy; } + public io.temporal.common.RetryOptions getRetryPolicy() { return retryPolicy; } + public String getCronSchedule() { return cronSchedule; } + public java.util.Map getMemo() { return memo; } + public io.temporal.common.SearchAttributes getSearchAttributes() { return searchAttributes; } + public io.temporal.common.Priority getPriority() { return priority; } + public io.temporal.common.VersioningOverride getVersioningOverride() { return versioningOverride; } + public java.time.Duration getStartDelay() { return startDelay; } + public io.temporal.workflow.UserMetadata getUserMetadata() { return userMetadata; } + public String getNamespace() { return namespace; } + public java.util.Map getHeaders() { return headers; } + public Builder toBuilder() { return newBuilder(this); } + public static Builder newBuilder(SignalWithStartWorkflowRequest value) { return new Builder(value); } + public static Builder newBuilder() { return new Builder(); } + public static final class Builder { + private Builder() {} + private Builder(SignalWithStartWorkflowRequest value) { + if (value == null) return; + this.workflow = value.workflow; + this.args = value.args; + this.id = value.id; + this.taskQueue = value.taskQueue; + this.signal = value.signal; + this.signalArgs = value.signalArgs; + this.executionTimeout = value.executionTimeout; + this.runTimeout = value.runTimeout; + this.taskTimeout = value.taskTimeout; + this.idReusePolicy = value.idReusePolicy; + this.idConflictPolicy = value.idConflictPolicy; + this.retryPolicy = value.retryPolicy; + this.cronSchedule = value.cronSchedule; + this.memo = value.memo; + this.searchAttributes = value.searchAttributes; + this.priority = value.priority; + this.versioningOverride = value.versioningOverride; + this.startDelay = value.startDelay; + this.userMetadata = value.userMetadata; + this.namespace = value.namespace; + this.headers = value.headers; + } + private String workflow = null; + public Builder setWorkflow(String value) { this.workflow = value; return this; } + private java.util.List args = null; + public Builder setArgs(java.util.List value) { this.args = value; return this; } + private String id = ""; + public Builder setId(String value) { this.id = value; return this; } + private String taskQueue = null; + public Builder setTaskQueue(String value) { this.taskQueue = value; return this; } + private String signal = ""; + public Builder setSignal(String value) { this.signal = value; return this; } + private java.util.List signalArgs = null; + public Builder setSignalArgs(java.util.List value) { this.signalArgs = value; return this; } + private java.time.Duration executionTimeout = null; + public Builder setExecutionTimeout(java.time.Duration value) { this.executionTimeout = value; return this; } + private java.time.Duration runTimeout = null; + public Builder setRunTimeout(java.time.Duration value) { this.runTimeout = value; return this; } + private java.time.Duration taskTimeout = null; + public Builder setTaskTimeout(java.time.Duration value) { this.taskTimeout = value; return this; } + private io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy = io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(1); + public Builder setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { this.idReusePolicy = value; return this; } + private io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy = null; + public Builder setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { this.idConflictPolicy = value; return this; } + private io.temporal.common.RetryOptions retryPolicy = null; + public Builder setRetryPolicy(io.temporal.common.RetryOptions value) { this.retryPolicy = value; return this; } + private String cronSchedule = null; + public Builder setCronSchedule(String value) { this.cronSchedule = value; return this; } + private java.util.Map memo = null; + public Builder setMemo(java.util.Map value) { this.memo = value; return this; } + private io.temporal.common.SearchAttributes searchAttributes = null; + public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { this.searchAttributes = value; return this; } + private io.temporal.common.Priority priority = null; + public Builder setPriority(io.temporal.common.Priority value) { this.priority = value; return this; } + private io.temporal.common.VersioningOverride versioningOverride = null; + public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { this.versioningOverride = value; return this; } + private java.time.Duration startDelay = null; + public Builder setStartDelay(java.time.Duration value) { this.startDelay = value; return this; } + private io.temporal.workflow.UserMetadata userMetadata = null; + public Builder setUserMetadata(io.temporal.workflow.UserMetadata value) { this.userMetadata = value; return this; } + private String namespace = null; + public Builder setNamespace(String value) { this.namespace = value; return this; } + private java.util.Map headers = null; + public Builder setHeaders(java.util.Map value) { this.headers = value; return this; } + public Builder setStaticSummary(Object value) { this.userMetadata = io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata).setStaticSummary(value).build(); return this; } + public Builder setStaticDetails(Object value) { this.userMetadata = io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata).setStaticDetails(value).build(); return this; } + public SignalWithStartWorkflowRequest build() { return new SignalWithStartWorkflowRequest(workflow, args, id, taskQueue, signal, signalArgs, executionTimeout, runTimeout, taskTimeout, idReusePolicy, idConflictPolicy, retryPolicy, cronSchedule, memo, searchAttributes, priority, versioningOverride, startDelay, userMetadata, namespace == null ? io.temporal.internal.nexus.system.TemporalModelConverters.workflowNamespace() : namespace, headers); } + } + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto(io.temporal.common.converter.DataConverter converter) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder(); + if (this.workflow != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_type", io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeToProto(converter, (this.workflow))); + if (this.args != null) io.temporal.workflow.NexgenRuntime.set(proto, "input", converter.toPayloads((this.args).toArray()).orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + if (this.id != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_id", (this.id)); + if (this.taskQueue != null) io.temporal.workflow.NexgenRuntime.set(proto, "task_queue", io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueToProto(converter, (this.taskQueue))); + if (this.signal != null) io.temporal.workflow.NexgenRuntime.set(proto, "signal_name", (this.signal)); + if (this.signalArgs != null) io.temporal.workflow.NexgenRuntime.set(proto, "signal_input", converter.toPayloads((this.signalArgs).toArray()).orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + if (this.executionTimeout != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_execution_timeout", io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto(converter, (this.executionTimeout))); + if (this.runTimeout != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_run_timeout", io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto(converter, (this.runTimeout))); + if (this.taskTimeout != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_task_timeout", io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto(converter, (this.taskTimeout))); + if (this.idReusePolicy != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_id_reuse_policy", (this.idReusePolicy).getNumber()); + if (this.idConflictPolicy != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_id_conflict_policy", (this.idConflictPolicy).getNumber()); + if (this.retryPolicy != null) io.temporal.workflow.NexgenRuntime.set(proto, "retry_policy", io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyToProto(converter, (this.retryPolicy))); + if (this.cronSchedule != null) io.temporal.workflow.NexgenRuntime.set(proto, "cron_schedule", (this.cronSchedule)); + if (this.memo != null) io.temporal.workflow.NexgenRuntime.set(proto, "memo", io.temporal.internal.nexus.system.TemporalModelConverters.memoToProto(converter, (this.memo))); + if (this.searchAttributes != null) io.temporal.workflow.NexgenRuntime.set(proto, "search_attributes", io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesToProto(converter, (this.searchAttributes))); + if (this.priority != null) io.temporal.workflow.NexgenRuntime.set(proto, "priority", io.temporal.internal.nexus.system.TemporalModelConverters.priorityToProto(converter, (this.priority))); + if (this.versioningOverride != null) io.temporal.workflow.NexgenRuntime.set(proto, "versioning_override", io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideToProto(converter, (this.versioningOverride))); + if (this.startDelay != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_start_delay", io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto(converter, (this.startDelay))); + if (this.userMetadata != null) io.temporal.workflow.NexgenRuntime.set(proto, "user_metadata", (this.userMetadata).toProto(converter)); + if (this.namespace != null) io.temporal.workflow.NexgenRuntime.set(proto, "namespace", (this.namespace)); + if (this.headers != null) io.temporal.workflow.NexgenRuntime.set(proto, "header", io.temporal.internal.nexus.system.TemporalModelConverters.headerToProto(converter, (this.headers))); + return proto.build(); + } + public static SignalWithStartWorkflowRequest fromProto(io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { + Builder builder = SignalWithStartWorkflowRequest.newBuilder(); + if (true) builder.setWorkflow(io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto(converter, (io.temporal.api.common.v1.WorkflowType) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_type"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "input")) builder.setArgs((java.util.List) (Object) io.temporal.workflow.NexgenRuntime.decodeSequence(io.temporal.workflow.NexgenRuntime.get(proto, "input"), converter, io.temporal.workflow.NexgenRuntime.argument(new com.fasterxml.jackson.core.type.TypeReference>() {}.getType(), 0))); + if (true) builder.setId((String) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id")); + if (true) builder.setTaskQueue(io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto(converter, (io.temporal.api.taskqueue.v1.TaskQueue) io.temporal.workflow.NexgenRuntime.get(proto, "task_queue"))); + if (true) builder.setSignal((String) io.temporal.workflow.NexgenRuntime.get(proto, "signal_name")); + if (io.temporal.workflow.NexgenRuntime.has(proto, "signal_input")) builder.setSignalArgs((java.util.List) (Object) io.temporal.workflow.NexgenRuntime.decodeSequence(io.temporal.workflow.NexgenRuntime.get(proto, "signal_input"), converter, io.temporal.workflow.NexgenRuntime.argument(new com.fasterxml.jackson.core.type.TypeReference>() {}.getType(), 0))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_execution_timeout")) builder.setExecutionTimeout(io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto(converter, (com.google.protobuf.Duration) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_execution_timeout"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_run_timeout")) builder.setRunTimeout(io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto(converter, (com.google.protobuf.Duration) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_run_timeout"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_task_timeout")) builder.setTaskTimeout(io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto(converter, (com.google.protobuf.Duration) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_task_timeout"))); + if (true) builder.setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(((com.google.protobuf.Descriptors.EnumValueDescriptor) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id_reuse_policy")).getNumber())); + if (true) builder.setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber(((com.google.protobuf.Descriptors.EnumValueDescriptor) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id_conflict_policy")).getNumber())); + if (io.temporal.workflow.NexgenRuntime.has(proto, "retry_policy")) builder.setRetryPolicy(io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyFromProto(converter, (io.temporal.api.common.v1.RetryPolicy) io.temporal.workflow.NexgenRuntime.get(proto, "retry_policy"))); + if (true) builder.setCronSchedule((String) io.temporal.workflow.NexgenRuntime.get(proto, "cron_schedule")); + if (io.temporal.workflow.NexgenRuntime.has(proto, "memo")) builder.setMemo(io.temporal.internal.nexus.system.TemporalModelConverters.memoFromProto(converter, (io.temporal.api.common.v1.Memo) io.temporal.workflow.NexgenRuntime.get(proto, "memo"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "search_attributes")) builder.setSearchAttributes(io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesFromProto(converter, (io.temporal.api.common.v1.SearchAttributes) io.temporal.workflow.NexgenRuntime.get(proto, "search_attributes"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "priority")) builder.setPriority(io.temporal.internal.nexus.system.TemporalModelConverters.priorityFromProto(converter, (io.temporal.api.common.v1.Priority) io.temporal.workflow.NexgenRuntime.get(proto, "priority"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "versioning_override")) builder.setVersioningOverride(io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideFromProto(converter, (io.temporal.api.workflow.v1.VersioningOverride) io.temporal.workflow.NexgenRuntime.get(proto, "versioning_override"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_start_delay")) builder.setStartDelay(io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto(converter, (com.google.protobuf.Duration) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_start_delay"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "user_metadata")) builder.setUserMetadata(io.temporal.workflow.UserMetadata.fromProto((io.temporal.api.sdk.v1.UserMetadata) io.temporal.workflow.NexgenRuntime.get(proto, "user_metadata"), converter, io.temporal.workflow.UserMetadata.class)); + if (true) builder.setNamespace((String) io.temporal.workflow.NexgenRuntime.get(proto, "namespace")); + if (io.temporal.workflow.NexgenRuntime.has(proto, "header")) builder.setHeaders(io.temporal.internal.nexus.system.TemporalModelConverters.headerFromProto(converter, (io.temporal.api.common.v1.Header) io.temporal.workflow.NexgenRuntime.get(proto, "header"))); + return builder.build(); + } + public static final class Converter implements io.temporal.common.converter.TransferTypeConverter { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.class; } + public Object toTransferType(SignalWithStartWorkflowRequest value) { return value == null ? null : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); } + public SignalWithStartWorkflowRequest fromTransferType(Object value, java.lang.reflect.Type valueType) { return value == null ? null : fromProto((io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value, io.temporal.workflow.NexgenRuntime.dataConverter(), valueType); } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java new file mode 100644 index 0000000000..619c4330e2 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java @@ -0,0 +1,57 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +@io.temporal.common.converter.TransferTypeConvertible(SignalWithStartWorkflowResponse.Converter.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SignalWithStartWorkflowResponse { + private final String runId; + private final Boolean started; + private final String firstExecutionRunId; + @com.fasterxml.jackson.annotation.JsonCreator + public SignalWithStartWorkflowResponse(@com.fasterxml.jackson.annotation.JsonProperty("runId") String runId, @com.fasterxml.jackson.annotation.JsonProperty("started") Boolean started, @com.fasterxml.jackson.annotation.JsonProperty("firstExecutionRunId") String firstExecutionRunId) { + this.runId = runId; + this.started = started; + this.firstExecutionRunId = firstExecutionRunId; + } + public String getRunId() { return runId; } + public Boolean getStarted() { return started; } + public String getFirstExecutionRunId() { return firstExecutionRunId; } + public Builder toBuilder() { return newBuilder(this); } + public static Builder newBuilder(SignalWithStartWorkflowResponse value) { return new Builder(value); } + public static Builder newBuilder() { return new Builder(); } + public static final class Builder { + private Builder() {} + private Builder(SignalWithStartWorkflowResponse value) { + if (value == null) return; + this.runId = value.runId; + this.started = value.started; + this.firstExecutionRunId = value.firstExecutionRunId; + } + private String runId = null; + public Builder setRunId(String value) { this.runId = value; return this; } + private Boolean started = null; + public Builder setStarted(Boolean value) { this.started = value; return this; } + private String firstExecutionRunId = ""; + public Builder setFirstExecutionRunId(String value) { this.firstExecutionRunId = value; return this; } + public SignalWithStartWorkflowResponse build() { return new SignalWithStartWorkflowResponse(runId, started, firstExecutionRunId); } + } + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto(io.temporal.common.converter.DataConverter converter) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); + if (this.runId != null) io.temporal.workflow.NexgenRuntime.set(proto, "run_id", (this.runId)); + if (this.started != null) io.temporal.workflow.NexgenRuntime.set(proto, "started", (this.started)); + if (this.firstExecutionRunId != null) io.temporal.workflow.NexgenRuntime.set(proto, "first_execution_run_id", (this.firstExecutionRunId)); + return proto.build(); + } + public static SignalWithStartWorkflowResponse fromProto(io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { + Builder builder = SignalWithStartWorkflowResponse.newBuilder(); + if (true) builder.setRunId((String) io.temporal.workflow.NexgenRuntime.get(proto, "run_id")); + if (true) builder.setStarted((Boolean) io.temporal.workflow.NexgenRuntime.get(proto, "started")); + if (true) builder.setFirstExecutionRunId((String) io.temporal.workflow.NexgenRuntime.get(proto, "first_execution_run_id")); + return builder.build(); + } + public static final class Converter implements io.temporal.common.converter.TransferTypeConverter { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.class; } + public Object toTransferType(SignalWithStartWorkflowResponse value) { return value == null ? null : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); } + public SignalWithStartWorkflowResponse fromTransferType(Object value, java.lang.reflect.Type valueType) { return value == null ? null : fromProto((io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value, io.temporal.workflow.NexgenRuntime.dataConverter(), valueType); } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java new file mode 100644 index 0000000000..4942c53178 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java @@ -0,0 +1,16 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** Generated operation dispatch and serialization context acquisition. */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SystemNexusOperations { + private SystemNexusOperations() {} + public static io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput execute(SystemNexusWorkflowOutboundInterceptor interceptor, io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input) { + if ("temporal.api.workflowservice.v1.WorkflowService".equals(input.getService()) && "SignalWithStartWorkflowExecution".equals(input.getOperation())) return (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput) interceptor.executeSignalWithStartWorkflow((io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput) input); + throw new IllegalArgumentException("Unsupported system Nexus operation: " + input.getService() + "/" + input.getOperation()); + } + public static io.temporal.payload.context.SerializationContext serializationContext(String service, String operation, Object request) { + if ("temporal.api.workflowservice.v1.WorkflowService".equals(service) && "SignalWithStartWorkflowExecution".equals(operation)) return io.temporal.internal.nexus.system.TemporalModelConverters.signalWithStartWorkflowSerializationContext((io.temporal.workflow.SignalWithStartWorkflowRequest) request); + return null; + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java new file mode 100644 index 0000000000..6413ed91c7 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java @@ -0,0 +1,12 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** Generated typed system Nexus hooks. */ +public interface SystemNexusWorkflowOutboundInterceptor { + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput executeNexusOperation(io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input); + default io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput executeSignalWithStartWorkflow(io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input) { return executeNexusOperation(input); } + abstract class Base implements SystemNexusWorkflowOutboundInterceptor { + protected abstract SystemNexusWorkflowOutboundInterceptor nextSystemNexusInterceptor(); + @Override public io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput executeSignalWithStartWorkflow(io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input) { return nextSystemNexusInterceptor().executeSignalWithStartWorkflow(input); } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java new file mode 100644 index 0000000000..c8aebb2e33 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java @@ -0,0 +1,58 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +@io.temporal.common.converter.TransferTypeConvertible(UserMetadata.Converter.class) +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class UserMetadata { + /** + * Single-line fixed summary for the workflow execution that may appear in UI and CLI. + * This can be in single-line Temporal Markdown format. + */ + private final Object staticSummary; + /** + * General fixed details for the workflow execution that may appear in UI and CLI. + * This can be in Temporal Markdown format and can span multiple lines. This value is + * fixed on the workflow execution and cannot be updated. + */ + private final Object staticDetails; + @com.fasterxml.jackson.annotation.JsonCreator + public UserMetadata(@com.fasterxml.jackson.annotation.JsonProperty("staticSummary") Object staticSummary, @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") Object staticDetails) { + this.staticSummary = staticSummary; + this.staticDetails = staticDetails; + } + public Object getStaticSummary() { return staticSummary; } + public Object getStaticDetails() { return staticDetails; } + public Builder toBuilder() { return newBuilder(this); } + public static Builder newBuilder(UserMetadata value) { return new Builder(value); } + public static Builder newBuilder() { return new Builder(); } + public static final class Builder { + private Builder() {} + private Builder(UserMetadata value) { + if (value == null) return; + this.staticSummary = value.staticSummary; + this.staticDetails = value.staticDetails; + } + private Object staticSummary = null; + public Builder setStaticSummary(Object value) { this.staticSummary = value; return this; } + private Object staticDetails = null; + public Builder setStaticDetails(Object value) { this.staticDetails = value; return this; } + public UserMetadata build() { return new UserMetadata(staticSummary, staticDetails); } + } + public io.temporal.api.sdk.v1.UserMetadata toProto(io.temporal.common.converter.DataConverter converter) { + io.temporal.api.sdk.v1.UserMetadata.Builder proto = io.temporal.api.sdk.v1.UserMetadata.newBuilder(); + if (this.staticSummary != null) io.temporal.workflow.NexgenRuntime.set(proto, "summary", converter.toPayload((this.staticSummary)).get()); + if (this.staticDetails != null) io.temporal.workflow.NexgenRuntime.set(proto, "details", converter.toPayload((this.staticDetails)).get()); + return proto.build(); + } + public static UserMetadata fromProto(io.temporal.api.sdk.v1.UserMetadata proto, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { + Builder builder = UserMetadata.newBuilder(); + if (io.temporal.workflow.NexgenRuntime.has(proto, "summary")) builder.setStaticSummary((Object) io.temporal.workflow.NexgenRuntime.decode(io.temporal.workflow.NexgenRuntime.get(proto, "summary"), converter, Object.class)); + if (io.temporal.workflow.NexgenRuntime.has(proto, "details")) builder.setStaticDetails((Object) io.temporal.workflow.NexgenRuntime.decode(io.temporal.workflow.NexgenRuntime.get(proto, "details"), converter, Object.class)); + return builder.build(); + } + public static final class Converter implements io.temporal.common.converter.TransferTypeConverter { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { return io.temporal.api.sdk.v1.UserMetadata.class; } + public Object toTransferType(UserMetadata value) { return value == null ? null : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); } + public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueType) { return value == null ? null : fromProto((io.temporal.api.sdk.v1.UserMetadata) value, io.temporal.workflow.NexgenRuntime.dataConverter(), valueType); } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java new file mode 100644 index 0000000000..843b617e47 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java @@ -0,0 +1,13 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public abstract class WorkflowOperations { + protected WorkflowOperations() {} + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow(io.temporal.workflow.SignalWithStartWorkflowRequest request) { + io.temporal.workflow.SignalWithStartWorkflowResponse result = (io.temporal.workflow.SignalWithStartWorkflowResponse) io.temporal.workflow.Workflow.newUntypedNexusServiceStub("temporal.api.workflowservice.v1.WorkflowService", io.temporal.workflow.NexusServiceOptions.newBuilder().setEndpoint("__temporal_system").build()).execute("SignalWithStartWorkflowExecution", io.temporal.workflow.SignalWithStartWorkflowResponse.class, io.temporal.workflow.SignalWithStartWorkflowResponse.class, request); + return io.temporal.workflow.Workflow.newUntypedExternalWorkflowStub(io.temporal.api.common.v1.WorkflowExecution.newBuilder().setWorkflowId(request.getId()).setRunId(result.getRunId() == null ? "" : result.getRunId()).build()); + } + public static io.temporal.payload.context.SerializationContext signalWithStartWorkflowSerializationContext(io.temporal.workflow.SignalWithStartWorkflowRequest request) { return io.temporal.internal.nexus.system.TemporalModelConverters.signalWithStartWorkflowSerializationContext(request); } + public static T withDataConverter(io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { return io.temporal.workflow.NexgenRuntime.withDataConverter(converter, action); } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java new file mode 100644 index 0000000000..f7b8a4996a --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java @@ -0,0 +1,8 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +@io.nexusrpc.Service(name = "temporal.api.workflowservice.v1.WorkflowService") +public interface WorkflowService { + @io.nexusrpc.Operation(name = "SignalWithStartWorkflowExecution") + io.temporal.workflow.SignalWithStartWorkflowResponse signalWithStartWorkflow(io.temporal.workflow.SignalWithStartWorkflowRequest request); +} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/system-nexus-roots.txt b/temporal-sdk/src/main/generated/io/temporal/workflow/system-nexus-roots.txt similarity index 100% rename from temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/system-nexus-roots.txt rename to temporal-sdk/src/main/generated/io/temporal/workflow/system-nexus-roots.txt diff --git a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java index 894f983649..dcb9f450a4 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java +++ b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java @@ -38,7 +38,7 @@ */ @Experimental public interface WorkflowOutboundCallsInterceptor - extends io.temporal.nexus.system.workflowservice.SystemNexusWorkflowOutboundInterceptor { + extends io.temporal.workflow.SystemNexusWorkflowOutboundInterceptor { final class ActivityInput { private final String activityName; diff --git a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java index fb55fbb354..f03b3a7522 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java +++ b/temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java @@ -17,7 +17,7 @@ /** Convenience base class for WorkflowOutboundCallsInterceptor implementations. */ public class WorkflowOutboundCallsInterceptorBase - extends io.temporal.nexus.system.workflowservice.SystemNexusWorkflowOutboundInterceptor.Base + extends io.temporal.workflow.SystemNexusWorkflowOutboundInterceptor.Base implements WorkflowOutboundCallsInterceptor { private final WorkflowOutboundCallsInterceptor next; diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java index 37671df6c6..fb0f7fe14a 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java @@ -9,7 +9,7 @@ import io.temporal.common.converter.RawValue; import io.temporal.internal.common.converter.TemporalTransferTypeDataConverter; import io.temporal.internal.payload.visitor.SystemNexusPayloads; -import io.temporal.nexus.system.workflowservice.NexgenRuntime; +import io.temporal.workflow.NexgenRuntime; import java.lang.reflect.Type; import java.util.Optional; import javax.annotation.Nonnull; diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java index 30cdb3e249..329fce0b92 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -6,8 +6,8 @@ import io.temporal.common.VersioningOverride; import io.temporal.common.converter.DataConverter; import io.temporal.internal.common.*; -import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest; import io.temporal.payload.context.WorkflowSerializationContext; +import io.temporal.workflow.SignalWithStartWorkflowRequest; import io.temporal.workflow.Workflow; import java.time.Duration; import java.util.LinkedHashMap; diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java index c1dd41479f..7e80782373 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/NexusServiceStubImpl.java @@ -105,8 +105,7 @@ private WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput exec WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input) { if (io.temporal.internal.nexus.system.SystemNexusDataConverter.ENDPOINT.equals( input.getEndpoint())) { - return io.temporal.nexus.system.workflowservice.SystemNexusOperations.execute( - outboundCallsInterceptor, input); + return io.temporal.workflow.SystemNexusOperations.execute(outboundCallsInterceptor, input); } return outboundCallsInterceptor.executeNexusOperation(input); } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowInvocationHandler.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowInvocationHandler.java deleted file mode 100644 index cb5f60a8e9..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowInvocationHandler.java +++ /dev/null @@ -1,145 +0,0 @@ -package io.temporal.internal.sync; - -import com.google.common.base.Defaults; -import io.temporal.common.CronSchedule; -import io.temporal.common.MethodRetry; -import io.temporal.common.RetryOptions; -import io.temporal.common.metadata.POJOWorkflowInterfaceMetadata; -import io.temporal.common.metadata.POJOWorkflowMethodMetadata; -import io.temporal.common.metadata.WorkflowMethodType; -import io.temporal.workflow.*; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -/** Captures two typed calls without executing either one before validation completes. */ -public final class SignalWithStartWorkflowInvocationHandler implements InvocationHandler { - private static final ThreadLocal CURRENT = new ThreadLocal<>(); - private final Class workflowInterface; - private final POJOWorkflowInterfaceMetadata metadata; - private final SignalWithStartWorkflowStub stub; - - private SignalWithStartWorkflowInvocationHandler( - Class workflowInterface, SignalWithStartWorkflowOptions options) { - this.workflowInterface = workflowInterface; - metadata = POJOWorkflowInterfaceMetadata.newInstance(workflowInterface); - POJOWorkflowMethodMetadata workflow = - metadata - .getWorkflowMethod() - .orElseThrow( - () -> - new IllegalArgumentException("Missing method annotated with @WorkflowMethod")); - Method method = workflow.getWorkflowMethod(); - SignalWithStartWorkflowOptions base = - options == null ? SignalWithStartWorkflowOptions.newBuilder().build() : options; - MethodRetry retry = method.getAnnotation(MethodRetry.class); - CronSchedule cron = method.getAnnotation(CronSchedule.class); - SignalWithStartWorkflowOptions merged = - base.toBuilder() - .setRetryOptions(RetryOptions.merge(retry, base.getRetryOptions())) - .setCronSchedule( - base.getCronSchedule() == null && cron != null - ? cron.value() - : base.getCronSchedule()) - .build(); - stub = new SignalWithStartWorkflowStubImpl(workflow.getName(), merged); - } - - @SuppressWarnings("unchecked") - public static T newStub(Class workflowInterface, SignalWithStartWorkflowOptions options) { - return (T) - Proxy.newProxyInstance( - workflowInterface.getClassLoader(), - new Class[] {workflowInterface}, - new SignalWithStartWorkflowInvocationHandler(workflowInterface, options)); - } - - private static SignalWithStartWorkflowInvocationHandler handler(Object target) { - if (target == null - || !Proxy.isProxyClass(target.getClass()) - || !(Proxy.getInvocationHandler(target) - instanceof SignalWithStartWorkflowInvocationHandler)) { - throw new IllegalArgumentException( - "Expected a stub created through Workflow.newSignalWithStartWorkflowStub"); - } - return (SignalWithStartWorkflowInvocationHandler) Proxy.getInvocationHandler(target); - } - - public static SignalWithStartWorkflowStub fromTyped(Object target) { - return handler(target).stub; - } - - @SuppressWarnings("unchecked") - public static T signalWithStart( - T target, Functions.Proc workflowCall, Functions.Proc signalCall) { - SignalWithStartWorkflowInvocationHandler handler = handler(target); - if (CURRENT.get() != null) - throw new IllegalStateException("Nested signal-with-start capture is not supported"); - Capture capture = new Capture(handler); - CURRENT.set(capture); - try { - workflowCall.apply(); - if (capture.startArgs == null) - throw new IllegalArgumentException("Expected exactly one workflow call"); - capture.signalPhase = true; - signalCall.apply(); - if (capture.signalArgs == null) - throw new IllegalArgumentException("Expected exactly one signal call"); - } finally { - CURRENT.remove(); - } - ExternalWorkflowStub external = - handler.stub.signalWithStart(capture.signalName, capture.signalArgs, capture.startArgs); - return (T) Workflow.newExternalWorkflowStub(handler.workflowInterface, external.getExecution()); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) { - if (method.getDeclaringClass() == Object.class) { - switch (method.getName()) { - case "toString": - return "SignalWithStartWorkflowStub{" + stub.getWorkflowType() + "}"; - case "hashCode": - return System.identityHashCode(proxy); - case "equals": - return proxy == args[0]; - default: - throw new IllegalArgumentException("Unsupported Object method"); - } - } - Capture capture = CURRENT.get(); - if (capture == null || capture.handler != this) - throw new IllegalStateException( - "Calls must use the target stub inside Workflow.signalWithStart"); - POJOWorkflowMethodMetadata entry = metadata.getMethodMetadata(method); - Object[] values = args == null ? new Object[0] : args.clone(); - if (!capture.signalPhase - && entry.getType() == WorkflowMethodType.WORKFLOW - && capture.startArgs == null) { - capture.startArgs = values; - } else if (capture.signalPhase - && entry.getType() == WorkflowMethodType.SIGNAL - && capture.signalArgs == null) { - capture.signalName = entry.getName(); - capture.signalArgs = values; - } else { - throw new IllegalArgumentException( - "Capture requires exactly one workflow call followed by exactly one signal call"); - } - return method.getReturnType() == Void.TYPE - ? null - : Defaults.defaultValue(method.getReturnType()); - } - - private static final class Capture { - private final SignalWithStartWorkflowInvocationHandler handler; - private boolean signalPhase; - private Object[] startArgs; - private String signalName; - private Object[] signalArgs; - - private Capture(SignalWithStartWorkflowInvocationHandler handler) { - this.handler = handler; - } - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowStubImpl.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowStubImpl.java deleted file mode 100644 index 215be6b386..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalWithStartWorkflowStubImpl.java +++ /dev/null @@ -1,96 +0,0 @@ -package io.temporal.internal.sync; - -import io.temporal.api.common.v1.WorkflowExecution; -import io.temporal.api.enums.v1.WorkflowIdReusePolicy; -import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest; -import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse; -import io.temporal.nexus.system.workflowservice.UserMetadata; -import io.temporal.nexus.system.workflowservice.WorkflowServiceOperations; -import io.temporal.workflow.*; -import java.util.Arrays; -import java.util.Objects; - -public final class SignalWithStartWorkflowStubImpl implements SignalWithStartWorkflowStub { - private final String workflowType; - private final SignalWithStartWorkflowOptions options; - - public SignalWithStartWorkflowStubImpl( - String workflowType, SignalWithStartWorkflowOptions options) { - this.workflowType = Objects.requireNonNull(workflowType, "workflowType"); - this.options = options == null ? SignalWithStartWorkflowOptions.newBuilder().build() : options; - } - - @Override - public String getWorkflowType() { - return workflowType; - } - - @Override - public SignalWithStartWorkflowOptions getOptions() { - return options; - } - - @SuppressWarnings("deprecation") - @Override - public ExternalWorkflowStub signalWithStart( - String signalName, Object[] signalArgs, Object... startArgs) { - WorkflowInternal.assertNotReadOnly("signal with start workflow"); - if (workflowType.isEmpty()) - throw new IllegalArgumentException("workflowType must not be empty"); - if (signalName == null || signalName.isEmpty()) - throw new IllegalArgumentException("signalName must not be empty"); - String id = - options.getWorkflowId() == null - ? Workflow.randomUUID().toString() - : options.getWorkflowId(); - if (id.isEmpty()) throw new IllegalArgumentException("workflowId must not be empty"); - String queue = - options.getTaskQueue() == null ? Workflow.getInfo().getTaskQueue() : options.getTaskQueue(); - if (queue.isEmpty()) throw new IllegalArgumentException("taskQueue must not be empty"); - if (options.getWorkflowIdReusePolicy() - == WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING - && options.getWorkflowIdConflictPolicy() != null) { - throw new IllegalArgumentException( - "workflowIdConflictPolicy cannot be combined with terminate-if-running"); - } - SignalWithStartWorkflowRequest request = - SignalWithStartWorkflowRequest.newBuilder() - .setWorkflow(workflowType) - .setSignal(signalName) - .setId(id) - .setTaskQueue(queue) - .setArgs(Arrays.asList(startArgs == null ? new Object[0] : startArgs.clone())) - .setSignalArgs(Arrays.asList(signalArgs == null ? new Object[0] : signalArgs.clone())) - .setExecutionTimeout(options.getWorkflowExecutionTimeout()) - .setRunTimeout(options.getWorkflowRunTimeout()) - .setTaskTimeout(options.getWorkflowTaskTimeout()) - .setIdReusePolicy( - options.getWorkflowIdReusePolicy() == null - ? WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE - : options.getWorkflowIdReusePolicy()) - .setIdConflictPolicy(options.getWorkflowIdConflictPolicy()) - .setRetryPolicy(options.getRetryOptions()) - .setCronSchedule(options.getCronSchedule()) - .setMemo(options.getMemo()) - .setSearchAttributes(options.getTypedSearchAttributes()) - .setPriority(options.getPriority()) - .setVersioningOverride(options.getVersioningOverride()) - .setStartDelay(options.getStartDelay()) - .setRequestId( - options.getRequestId() == null - ? Workflow.randomUUID().toString() - : options.getRequestId()) - .setUserMetadata( - UserMetadata.newBuilder() - .setStaticSummary(options.getStaticSummary()) - .setStaticDetails(options.getStaticDetails()) - .build()) - .build(); - SignalWithStartWorkflowResponse response = - WorkflowServiceOperations.signalWithStartWorkflow(request); - WorkflowExecution.Builder execution = WorkflowExecution.newBuilder().setWorkflowId(id); - if (response.getRunId() != null && !response.getRunId().isEmpty()) - execution.setRunId(response.getRunId()); - return Workflow.newUntypedExternalWorkflowStub(execution.build()); - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java index cfba04d403..a7eff474d2 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java @@ -833,7 +833,7 @@ public ExecuteNexusOperationOutput executeNexusOperation( if (io.temporal.internal.nexus.system.SystemNexusDataConverter.ENDPOINT.equals( input.getEndpoint())) { io.temporal.payload.context.SerializationContext context = - io.temporal.nexus.system.workflowservice.SystemNexusOperations.serializationContext( + io.temporal.workflow.SystemNexusOperations.serializationContext( input.getService(), input.getOperation(), input.getArg()); userMetadataDataConverter = context == null ? dataConverter : dataConverter.withContext(context); diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/NexgenRuntime.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/NexgenRuntime.java deleted file mode 100644 index f001d56b23..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/NexgenRuntime.java +++ /dev/null @@ -1,306 +0,0 @@ -// Generated by nexgen. DO NOT EDIT! -package io.temporal.nexus.system.workflowservice; - -/** Shared conversion helpers for generated WIT models. */ -@SuppressWarnings({"unchecked", "rawtypes"}) -public final class NexgenRuntime { - private NexgenRuntime() {} - - private static final ThreadLocal CONVERTER = - new ThreadLocal<>(); - - public static io.temporal.common.converter.DataConverter dataConverter() { - io.temporal.common.converter.DataConverter value = CONVERTER.get(); - return value == null - ? io.temporal.common.converter.DefaultDataConverter.STANDARD_INSTANCE - : value; - } - - public static T withDataConverter( - io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { - io.temporal.common.converter.DataConverter previous = CONVERTER.get(); - CONVERTER.set(converter); - try { - return action.get(); - } finally { - if (previous == null) CONVERTER.remove(); - else CONVERTER.set(previous); - } - } - - public static java.lang.reflect.Type parameterized( - final Class raw, final java.lang.reflect.Type... arguments) { - return new java.lang.reflect.ParameterizedType() { - public java.lang.reflect.Type getRawType() { - return raw; - } - - public java.lang.reflect.Type getOwnerType() { - return raw.getDeclaringClass(); - } - - public java.lang.reflect.Type[] getActualTypeArguments() { - return arguments.clone(); - } - }; - } - - public static java.lang.reflect.Type argument(java.lang.reflect.Type type, int index) { - return type instanceof java.lang.reflect.ParameterizedType - ? ((java.lang.reflect.ParameterizedType) type).getActualTypeArguments()[index] - : Object.class; - } - - public static Object get(com.google.protobuf.Message message, String name) { - return message.getField(field(message, name)); - } - - public static boolean has(com.google.protobuf.Message message, String name) { - com.google.protobuf.Descriptors.FieldDescriptor field = field(message, name); - return field.isRepeated() ? message.getRepeatedFieldCount(field) > 0 : message.hasField(field); - } - - private static com.google.protobuf.Descriptors.FieldDescriptor field( - com.google.protobuf.MessageOrBuilder message, String name) { - com.google.protobuf.Descriptors.FieldDescriptor field = - message.getDescriptorForType().findFieldByName(name); - if (field == null) throw new IllegalArgumentException("Unknown protobuf field: " + name); - return field; - } - - public static void set(com.google.protobuf.Message.Builder builder, String name, Object value) { - com.google.protobuf.Descriptors.FieldDescriptor field = field(builder, name); - if (field.isMapField() && value instanceof java.util.Map) { - for (Object raw : ((java.util.Map) value).entrySet()) { - java.util.Map.Entry entry = (java.util.Map.Entry) raw; - com.google.protobuf.Message.Builder entryBuilder = builder.newBuilderForField(field); - set(entryBuilder, "key", entry.getKey()); - set(entryBuilder, "value", entry.getValue()); - builder.addRepeatedField(field, entryBuilder.build()); - } - } else if (field.isRepeated()) { - java.util.List normalized = new java.util.ArrayList<>(); - for (Object item : (java.util.List) value) normalized.add(wireValue(field, item)); - builder.setField(field, normalized); - } else { - builder.setField(field, wireValue(field, value)); - } - } - - private static Object wireValue( - com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { - if (field.getJavaType() == com.google.protobuf.Descriptors.FieldDescriptor.JavaType.ENUM) { - if (value instanceof String) { - String name = (String) value; - com.google.protobuf.Descriptors.EnumValueDescriptor member = - field.getEnumType().findValueByName(name); - if (member != null) return member; - for (com.google.protobuf.Descriptors.EnumValueDescriptor candidate : - field.getEnumType().getValues()) - if (candidate.getName().endsWith("_" + name)) return candidate; - throw new IllegalArgumentException("Unknown enum value: " + name); - } - if (value instanceof Number) - return field.getEnumType().findValueByNumberCreatingIfUnknown(((Number) value).intValue()); - if (value instanceof com.google.protobuf.ProtocolMessageEnum) - return ((com.google.protobuf.ProtocolMessageEnum) value).getValueDescriptor(); - } - if (value instanceof Number) { - switch (field.getJavaType()) { - case INT: - return ((Number) value).intValue(); - case LONG: - return ((Number) value).longValue(); - case FLOAT: - return ((Number) value).floatValue(); - case DOUBLE: - return ((Number) value).doubleValue(); - default: - break; - } - } - return value; - } - - public static java.util.Map protoMap(Object value) { - java.util.Map result = new java.util.LinkedHashMap<>(); - for (com.google.protobuf.Message entry : (java.util.List) value) - result.put(get(entry, "key"), get(entry, "value")); - return result; - } - - public static java.util.List map( - java.util.List values, java.util.function.Function function) { - java.util.List result = new java.util.ArrayList<>(values.size()); - for (A value : values) result.add(function.apply(value)); - return result; - } - - public static java.util.Map mapValues( - java.util.Map values, - java.util.function.Function key, - java.util.function.Function value) { - java.util.Map result = new java.util.LinkedHashMap<>(); - for (java.util.Map.Entry entry : values.entrySet()) - result.put(key.apply(entry.getKey()), value.apply(entry.getValue())); - return result; - } - - public static final class FunctionReference { - private final F callable; - private final N name; - - private FunctionReference(F callable, N name) { - this.callable = callable; - this.name = name; - } - - public static FunctionReference callable(F value) { - return new FunctionReference<>(java.util.Objects.requireNonNull(value), null); - } - - public static FunctionReference named(N value) { - return new FunctionReference<>(null, java.util.Objects.requireNonNull(value)); - } - - public boolean isNamed() { - return name != null; - } - - public F getCallable() { - return callable; - } - - public N getName() { - return name; - } - } - - public interface Flag { - long getBit(); - } - - public static long flags(java.util.Set> values) { - long result = 0; - for (Enum value : values) result |= ((Flag) value).getBit(); - return result; - } - - public static & Flag> java.util.EnumSet flagsFromNumber( - long bits, Class type) { - java.util.EnumSet result = java.util.EnumSet.noneOf(type); - for (E value : type.getEnumConstants()) if ((bits & value.getBit()) != 0) result.add(value); - return result; - } - - public static Object decode( - Object value, - io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type type) { - Class raw = - type instanceof Class - ? (Class) type - : type instanceof java.lang.reflect.ParameterizedType - ? (Class) ((java.lang.reflect.ParameterizedType) type).getRawType() - : Object.class; - if (value instanceof io.temporal.api.common.v1.Payload) - return converter.fromPayload((io.temporal.api.common.v1.Payload) value, raw, type); - io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; - return converter.fromPayloads(0, java.util.Optional.of(payloads), raw, type); - } - - public static java.util.List decodeSequence( - Object value, - io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type element) { - io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; - Class raw = - element instanceof Class - ? (Class) element - : element instanceof java.lang.reflect.ParameterizedType - ? (Class) ((java.lang.reflect.ParameterizedType) element).getRawType() - : Object.class; - java.util.List result = new java.util.ArrayList<>(); - for (io.temporal.api.common.v1.Payload payload : payloads.getPayloadsList()) - result.add(converter.fromPayload(payload, raw, element)); - return result; - } - - @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Result.Deserializer.class) - public static final class Result { - private final boolean ok; - private final Object value; - - private Result(boolean ok, Object value) { - this.ok = ok; - this.value = value; - } - - public static Result ok(O value) { - return new Result<>(true, value); - } - - public static Result err(E value) { - return new Result<>(false, value); - } - - @com.fasterxml.jackson.annotation.JsonIgnore - public boolean isOk() { - return ok; - } - - public String getTag() { - return ok ? "ok" : "err"; - } - - public Object getValue() { - return value; - } - - @com.fasterxml.jackson.annotation.JsonIgnore - public O getOk() { - if (!ok) throw new IllegalStateException("Error result"); - return (O) value; - } - - @com.fasterxml.jackson.annotation.JsonIgnore - public E getErr() { - if (ok) throw new IllegalStateException("Success result"); - return (E) value; - } - - public static final class Deserializer - extends com.fasterxml.jackson.databind.JsonDeserializer - implements com.fasterxml.jackson.databind.deser.ContextualDeserializer { - private final com.fasterxml.jackson.databind.JavaType type; - - public Deserializer() { - this(null); - } - - private Deserializer(com.fasterxml.jackson.databind.JavaType type) { - this.type = type; - } - - public com.fasterxml.jackson.databind.JsonDeserializer createContextual( - com.fasterxml.jackson.databind.DeserializationContext context, - com.fasterxml.jackson.databind.BeanProperty property) { - return new Deserializer(context.getContextualType()); - } - - public Result deserialize( - com.fasterxml.jackson.core.JsonParser parser, - com.fasterxml.jackson.databind.DeserializationContext context) - throws java.io.IOException { - com.fasterxml.jackson.databind.JsonNode node = parser.getCodec().readTree(parser); - String tag = node.get("tag").asText(); - if (!"ok".equals(tag) && !"err".equals(tag)) - throw new java.io.IOException("Unknown result tag: " + tag); - boolean ok = "ok".equals(tag); - Object value = - context.readTreeAsValue(node.get("value"), type.containedTypeOrUnknown(ok ? 0 : 1)); - return new Result(ok, value); - } - } - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowRequest.java deleted file mode 100644 index 856d8215e4..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowRequest.java +++ /dev/null @@ -1,750 +0,0 @@ -// Generated by nexgen v0.2.9. DO NOT EDIT! -package io.temporal.nexus.system.workflowservice; - -/** Request fields for signaling a workflow, starting it first if needed. */ -@io.temporal.common.converter.TransferTypeConvertible( - SignalWithStartWorkflowRequest.Converter.class) -@SuppressWarnings({"unchecked", "rawtypes"}) -public final class SignalWithStartWorkflowRequest { - private final String workflow; - - /** Arguments for the workflow. */ - private final java.util.List args; - - /** Unique identifier for the workflow execution. */ - private final String id; - - /** Task queue to run the workflow on. */ - private final String taskQueue; - - private final String signal; - - /** Arguments for the signal. */ - private final java.util.List signalArgs; - - /** Total workflow execution timeout, including retries and continue-as-new. */ - private final java.time.Duration executionTimeout; - - /** Timeout of a single workflow run. */ - private final java.time.Duration runTimeout; - - /** Timeout of a single workflow task. */ - private final java.time.Duration taskTimeout; - - /** Request ID used to deduplicate workflow start requests. */ - private final String requestId; - - /** Behavior when a closed workflow with the same ID exists. Default is allow-duplicate. */ - private final io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy; - - /** - * Behavior when a workflow is currently running with the same ID. Set to use-existing for - * idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is - * terminate-if-running. - */ - private final io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy; - - /** Retry policy for the workflow. */ - private final io.temporal.common.RetryOptions retryPolicy; - - /** Cron schedule for recurring workflow executions. See https://docs.temporal.io/cron-job. */ - private final String cronSchedule; - - /** Memo for the workflow. */ - private final java.util.Map memo; - - /** Typed search attributes for the workflow. */ - private final io.temporal.common.SearchAttributes searchAttributes; - - /** Priority of the workflow execution. */ - private final io.temporal.common.Priority priority; - - /** Override for workflow versioning behavior. */ - private final io.temporal.common.VersioningOverride versioningOverride; - - /** Amount of time to wait before starting the workflow. This does not work with cron-schedule. */ - private final java.time.Duration startDelay; - - private final io.temporal.nexus.system.workflowservice.UserMetadata userMetadata; - private final String namespace; - private final java.util.Map headers; - - @com.fasterxml.jackson.annotation.JsonCreator - public SignalWithStartWorkflowRequest( - @com.fasterxml.jackson.annotation.JsonProperty("workflow") String workflow, - @com.fasterxml.jackson.annotation.JsonProperty("args") java.util.List args, - @com.fasterxml.jackson.annotation.JsonProperty("id") String id, - @com.fasterxml.jackson.annotation.JsonProperty("taskQueue") String taskQueue, - @com.fasterxml.jackson.annotation.JsonProperty("signal") String signal, - @com.fasterxml.jackson.annotation.JsonProperty("signalArgs") - java.util.List signalArgs, - @com.fasterxml.jackson.annotation.JsonProperty("executionTimeout") - java.time.Duration executionTimeout, - @com.fasterxml.jackson.annotation.JsonProperty("runTimeout") java.time.Duration runTimeout, - @com.fasterxml.jackson.annotation.JsonProperty("taskTimeout") java.time.Duration taskTimeout, - @com.fasterxml.jackson.annotation.JsonProperty("requestId") String requestId, - @com.fasterxml.jackson.annotation.JsonProperty("idReusePolicy") - io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy, - @com.fasterxml.jackson.annotation.JsonProperty("idConflictPolicy") - io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy, - @com.fasterxml.jackson.annotation.JsonProperty("retryPolicy") - io.temporal.common.RetryOptions retryPolicy, - @com.fasterxml.jackson.annotation.JsonProperty("cronSchedule") String cronSchedule, - @com.fasterxml.jackson.annotation.JsonProperty("memo") java.util.Map memo, - @com.fasterxml.jackson.annotation.JsonProperty("searchAttributes") - io.temporal.common.SearchAttributes searchAttributes, - @com.fasterxml.jackson.annotation.JsonProperty("priority") - io.temporal.common.Priority priority, - @com.fasterxml.jackson.annotation.JsonProperty("versioningOverride") - io.temporal.common.VersioningOverride versioningOverride, - @com.fasterxml.jackson.annotation.JsonProperty("startDelay") java.time.Duration startDelay, - @com.fasterxml.jackson.annotation.JsonProperty("userMetadata") - io.temporal.nexus.system.workflowservice.UserMetadata userMetadata, - @com.fasterxml.jackson.annotation.JsonProperty("namespace") String namespace, - @com.fasterxml.jackson.annotation.JsonProperty("headers") - java.util.Map headers) { - this.workflow = workflow; - this.args = args; - this.id = id; - this.taskQueue = taskQueue; - this.signal = signal; - this.signalArgs = signalArgs; - this.executionTimeout = executionTimeout; - this.runTimeout = runTimeout; - this.taskTimeout = taskTimeout; - this.requestId = requestId; - this.idReusePolicy = idReusePolicy; - this.idConflictPolicy = idConflictPolicy; - this.retryPolicy = retryPolicy; - this.cronSchedule = cronSchedule; - this.memo = memo; - this.searchAttributes = searchAttributes; - this.priority = priority; - this.versioningOverride = versioningOverride; - this.startDelay = startDelay; - this.userMetadata = userMetadata; - this.namespace = namespace; - this.headers = headers; - } - - public String getWorkflow() { - return workflow; - } - - public java.util.List getArgs() { - return args; - } - - public String getId() { - return id; - } - - public String getTaskQueue() { - return taskQueue; - } - - public String getSignal() { - return signal; - } - - public java.util.List getSignalArgs() { - return signalArgs; - } - - public java.time.Duration getExecutionTimeout() { - return executionTimeout; - } - - public java.time.Duration getRunTimeout() { - return runTimeout; - } - - public java.time.Duration getTaskTimeout() { - return taskTimeout; - } - - public String getRequestId() { - return requestId; - } - - public io.temporal.api.enums.v1.WorkflowIdReusePolicy getIdReusePolicy() { - return idReusePolicy; - } - - public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getIdConflictPolicy() { - return idConflictPolicy; - } - - public io.temporal.common.RetryOptions getRetryPolicy() { - return retryPolicy; - } - - public String getCronSchedule() { - return cronSchedule; - } - - public java.util.Map getMemo() { - return memo; - } - - public io.temporal.common.SearchAttributes getSearchAttributes() { - return searchAttributes; - } - - public io.temporal.common.Priority getPriority() { - return priority; - } - - public io.temporal.common.VersioningOverride getVersioningOverride() { - return versioningOverride; - } - - public java.time.Duration getStartDelay() { - return startDelay; - } - - public io.temporal.nexus.system.workflowservice.UserMetadata getUserMetadata() { - return userMetadata; - } - - public String getNamespace() { - return namespace; - } - - public java.util.Map getHeaders() { - return headers; - } - - public Builder toBuilder() { - return newBuilder(this); - } - - public static Builder newBuilder(SignalWithStartWorkflowRequest value) { - return new Builder(value); - } - - public static Builder newBuilder() { - return new Builder(); - } - - public static final class Builder { - private Builder() {} - - private Builder(SignalWithStartWorkflowRequest value) { - if (value == null) return; - this.workflow = value.workflow; - this.args = value.args; - this.id = value.id; - this.taskQueue = value.taskQueue; - this.signal = value.signal; - this.signalArgs = value.signalArgs; - this.executionTimeout = value.executionTimeout; - this.runTimeout = value.runTimeout; - this.taskTimeout = value.taskTimeout; - this.requestId = value.requestId; - this.idReusePolicy = value.idReusePolicy; - this.idConflictPolicy = value.idConflictPolicy; - this.retryPolicy = value.retryPolicy; - this.cronSchedule = value.cronSchedule; - this.memo = value.memo; - this.searchAttributes = value.searchAttributes; - this.priority = value.priority; - this.versioningOverride = value.versioningOverride; - this.startDelay = value.startDelay; - this.userMetadata = value.userMetadata; - this.namespace = value.namespace; - this.headers = value.headers; - } - - private String workflow = null; - - public Builder setWorkflow(String value) { - this.workflow = value; - return this; - } - - private java.util.List args = null; - - public Builder setArgs(java.util.List value) { - this.args = value; - return this; - } - - private String id = ""; - - public Builder setId(String value) { - this.id = value; - return this; - } - - private String taskQueue = null; - - public Builder setTaskQueue(String value) { - this.taskQueue = value; - return this; - } - - private String signal = ""; - - public Builder setSignal(String value) { - this.signal = value; - return this; - } - - private java.util.List signalArgs = null; - - public Builder setSignalArgs(java.util.List value) { - this.signalArgs = value; - return this; - } - - private java.time.Duration executionTimeout = null; - - public Builder setExecutionTimeout(java.time.Duration value) { - this.executionTimeout = value; - return this; - } - - private java.time.Duration runTimeout = null; - - public Builder setRunTimeout(java.time.Duration value) { - this.runTimeout = value; - return this; - } - - private java.time.Duration taskTimeout = null; - - public Builder setTaskTimeout(java.time.Duration value) { - this.taskTimeout = value; - return this; - } - - private String requestId = null; - - public Builder setRequestId(String value) { - this.requestId = value; - return this; - } - - private io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy = - io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(1); - - public Builder setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { - this.idReusePolicy = value; - return this; - } - - private io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy = null; - - public Builder setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { - this.idConflictPolicy = value; - return this; - } - - private io.temporal.common.RetryOptions retryPolicy = null; - - public Builder setRetryPolicy(io.temporal.common.RetryOptions value) { - this.retryPolicy = value; - return this; - } - - private String cronSchedule = null; - - public Builder setCronSchedule(String value) { - this.cronSchedule = value; - return this; - } - - private java.util.Map memo = null; - - public Builder setMemo(java.util.Map value) { - this.memo = value; - return this; - } - - private io.temporal.common.SearchAttributes searchAttributes = null; - - public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { - this.searchAttributes = value; - return this; - } - - private io.temporal.common.Priority priority = null; - - public Builder setPriority(io.temporal.common.Priority value) { - this.priority = value; - return this; - } - - private io.temporal.common.VersioningOverride versioningOverride = null; - - public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { - this.versioningOverride = value; - return this; - } - - private java.time.Duration startDelay = null; - - public Builder setStartDelay(java.time.Duration value) { - this.startDelay = value; - return this; - } - - private io.temporal.nexus.system.workflowservice.UserMetadata userMetadata = null; - - public Builder setUserMetadata(io.temporal.nexus.system.workflowservice.UserMetadata value) { - this.userMetadata = value; - return this; - } - - private String namespace = null; - - public Builder setNamespace(String value) { - this.namespace = value; - return this; - } - - private java.util.Map headers = null; - - public Builder setHeaders(java.util.Map value) { - this.headers = value; - return this; - } - - public Builder setStaticSummary(Object value) { - this.userMetadata = - io.temporal.nexus.system.workflowservice.UserMetadata.newBuilder(this.userMetadata) - .setStaticSummary(value) - .build(); - return this; - } - - public Builder setStaticDetails(Object value) { - this.userMetadata = - io.temporal.nexus.system.workflowservice.UserMetadata.newBuilder(this.userMetadata) - .setStaticDetails(value) - .build(); - return this; - } - - public SignalWithStartWorkflowRequest build() { - return new SignalWithStartWorkflowRequest( - workflow, - args, - id, - taskQueue, - signal, - signalArgs, - executionTimeout, - runTimeout, - taskTimeout, - requestId, - idReusePolicy, - idConflictPolicy, - retryPolicy, - cronSchedule, - memo, - searchAttributes, - priority, - versioningOverride, - startDelay, - userMetadata, - namespace == null - ? io.temporal.internal.nexus.system.TemporalModelConverters.workflowNamespace() - : namespace, - headers); - } - } - - public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto( - io.temporal.common.converter.DataConverter converter) { - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.Builder proto = - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder(); - if (this.workflow != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "workflow_type", - io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeToProto( - converter, (this.workflow))); - if (this.args != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "input", - converter - .toPayloads((this.args).toArray()) - .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); - if (this.id != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set(proto, "workflow_id", (this.id)); - if (this.taskQueue != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "task_queue", - io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueToProto( - converter, (this.taskQueue))); - if (this.signal != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "signal_name", (this.signal)); - if (this.signalArgs != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "signal_input", - converter - .toPayloads((this.signalArgs).toArray()) - .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); - if (this.executionTimeout != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "workflow_execution_timeout", - io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - converter, (this.executionTimeout))); - if (this.runTimeout != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "workflow_run_timeout", - io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - converter, (this.runTimeout))); - if (this.taskTimeout != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "workflow_task_timeout", - io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - converter, (this.taskTimeout))); - if (this.requestId != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "request_id", (this.requestId)); - if (this.idReusePolicy != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "workflow_id_reuse_policy", (this.idReusePolicy).getNumber()); - if (this.idConflictPolicy != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "workflow_id_conflict_policy", (this.idConflictPolicy).getNumber()); - if (this.retryPolicy != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "retry_policy", - io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyToProto( - converter, (this.retryPolicy))); - if (this.cronSchedule != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "cron_schedule", (this.cronSchedule)); - if (this.memo != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "memo", - io.temporal.internal.nexus.system.TemporalModelConverters.memoToProto( - converter, (this.memo))); - if (this.searchAttributes != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "search_attributes", - io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesToProto( - converter, (this.searchAttributes))); - if (this.priority != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "priority", - io.temporal.internal.nexus.system.TemporalModelConverters.priorityToProto( - converter, (this.priority))); - if (this.versioningOverride != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "versioning_override", - io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideToProto( - converter, (this.versioningOverride))); - if (this.startDelay != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "workflow_start_delay", - io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - converter, (this.startDelay))); - if (this.userMetadata != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "user_metadata", (this.userMetadata).toProto(converter)); - if (this.namespace != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "namespace", (this.namespace)); - if (this.headers != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, - "header", - io.temporal.internal.nexus.system.TemporalModelConverters.headerToProto( - converter, (this.headers))); - return proto.build(); - } - - public static SignalWithStartWorkflowRequest fromProto( - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto, - io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type modelType) { - Builder builder = SignalWithStartWorkflowRequest.newBuilder(); - if (true) - builder.setWorkflow( - io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto( - converter, - (io.temporal.api.common.v1.WorkflowType) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "workflow_type"))); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "input")) - builder.setArgs( - (java.util.List) - (Object) - io.temporal.nexus.system.workflowservice.NexgenRuntime.decodeSequence( - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "input"), - converter, - io.temporal.nexus.system.workflowservice.NexgenRuntime.argument( - new com.fasterxml.jackson.core.type.TypeReference< - java.util.List>() {}.getType(), - 0))); - if (true) - builder.setId( - (String) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "workflow_id")); - if (true) - builder.setTaskQueue( - io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto( - converter, - (io.temporal.api.taskqueue.v1.TaskQueue) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "task_queue"))); - if (true) - builder.setSignal( - (String) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "signal_name")); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "signal_input")) - builder.setSignalArgs( - (java.util.List) - (Object) - io.temporal.nexus.system.workflowservice.NexgenRuntime.decodeSequence( - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "signal_input"), - converter, - io.temporal.nexus.system.workflowservice.NexgenRuntime.argument( - new com.fasterxml.jackson.core.type.TypeReference< - java.util.List>() {}.getType(), - 0))); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has( - proto, "workflow_execution_timeout")) - builder.setExecutionTimeout( - io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, - (com.google.protobuf.Duration) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "workflow_execution_timeout"))); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "workflow_run_timeout")) - builder.setRunTimeout( - io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, - (com.google.protobuf.Duration) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "workflow_run_timeout"))); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "workflow_task_timeout")) - builder.setTaskTimeout( - io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, - (com.google.protobuf.Duration) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "workflow_task_timeout"))); - if (true) - builder.setRequestId( - (String) io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "request_id")); - if (true) - builder.setIdReusePolicy( - io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( - ((com.google.protobuf.Descriptors.EnumValueDescriptor) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "workflow_id_reuse_policy")) - .getNumber())); - if (true) - builder.setIdConflictPolicy( - io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber( - ((com.google.protobuf.Descriptors.EnumValueDescriptor) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "workflow_id_conflict_policy")) - .getNumber())); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "retry_policy")) - builder.setRetryPolicy( - io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyFromProto( - converter, - (io.temporal.api.common.v1.RetryPolicy) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "retry_policy"))); - if (true) - builder.setCronSchedule( - (String) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "cron_schedule")); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "memo")) - builder.setMemo( - io.temporal.internal.nexus.system.TemporalModelConverters.memoFromProto( - converter, - (io.temporal.api.common.v1.Memo) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "memo"))); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "search_attributes")) - builder.setSearchAttributes( - io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesFromProto( - converter, - (io.temporal.api.common.v1.SearchAttributes) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "search_attributes"))); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "priority")) - builder.setPriority( - io.temporal.internal.nexus.system.TemporalModelConverters.priorityFromProto( - converter, - (io.temporal.api.common.v1.Priority) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "priority"))); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "versioning_override")) - builder.setVersioningOverride( - io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideFromProto( - converter, - (io.temporal.api.workflow.v1.VersioningOverride) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "versioning_override"))); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "workflow_start_delay")) - builder.setStartDelay( - io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, - (com.google.protobuf.Duration) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "workflow_start_delay"))); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "user_metadata")) - builder.setUserMetadata( - io.temporal.nexus.system.workflowservice.UserMetadata.fromProto( - (io.temporal.api.sdk.v1.UserMetadata) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "user_metadata"), - converter, - io.temporal.nexus.system.workflowservice.UserMetadata.class)); - if (true) - builder.setNamespace( - (String) io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "namespace")); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "header")) - builder.setHeaders( - io.temporal.internal.nexus.system.TemporalModelConverters.headerFromProto( - converter, - (io.temporal.api.common.v1.Header) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "header"))); - return builder.build(); - } - - public static final class Converter - implements io.temporal.common.converter.TransferTypeConverter< - SignalWithStartWorkflowRequest> { - public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { - return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.class; - } - - public Object toTransferType(SignalWithStartWorkflowRequest value) { - return value == null - ? null - : value.toProto(io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter()); - } - - public SignalWithStartWorkflowRequest fromTransferType( - Object value, java.lang.reflect.Type valueType) { - return value == null - ? null - : fromProto( - (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value, - io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter(), - valueType); - } - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowResponse.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowResponse.java deleted file mode 100644 index 9e25e00d48..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SignalWithStartWorkflowResponse.java +++ /dev/null @@ -1,139 +0,0 @@ -// Generated by nexgen v0.2.9. DO NOT EDIT! -package io.temporal.nexus.system.workflowservice; - -@io.temporal.common.converter.TransferTypeConvertible( - SignalWithStartWorkflowResponse.Converter.class) -@SuppressWarnings({"unchecked", "rawtypes"}) -public final class SignalWithStartWorkflowResponse { - private final String runId; - private final Boolean started; - private final String firstExecutionRunId; - - @com.fasterxml.jackson.annotation.JsonCreator - public SignalWithStartWorkflowResponse( - @com.fasterxml.jackson.annotation.JsonProperty("runId") String runId, - @com.fasterxml.jackson.annotation.JsonProperty("started") Boolean started, - @com.fasterxml.jackson.annotation.JsonProperty("firstExecutionRunId") - String firstExecutionRunId) { - this.runId = runId; - this.started = started; - this.firstExecutionRunId = firstExecutionRunId; - } - - public String getRunId() { - return runId; - } - - public Boolean getStarted() { - return started; - } - - public String getFirstExecutionRunId() { - return firstExecutionRunId; - } - - public Builder toBuilder() { - return newBuilder(this); - } - - public static Builder newBuilder(SignalWithStartWorkflowResponse value) { - return new Builder(value); - } - - public static Builder newBuilder() { - return new Builder(); - } - - public static final class Builder { - private Builder() {} - - private Builder(SignalWithStartWorkflowResponse value) { - if (value == null) return; - this.runId = value.runId; - this.started = value.started; - this.firstExecutionRunId = value.firstExecutionRunId; - } - - private String runId = null; - - public Builder setRunId(String value) { - this.runId = value; - return this; - } - - private Boolean started = null; - - public Builder setStarted(Boolean value) { - this.started = value; - return this; - } - - private String firstExecutionRunId = ""; - - public Builder setFirstExecutionRunId(String value) { - this.firstExecutionRunId = value; - return this; - } - - public SignalWithStartWorkflowResponse build() { - return new SignalWithStartWorkflowResponse(runId, started, firstExecutionRunId); - } - } - - public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto( - io.temporal.common.converter.DataConverter converter) { - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); - if (this.runId != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set(proto, "run_id", (this.runId)); - if (this.started != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set(proto, "started", (this.started)); - if (this.firstExecutionRunId != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "first_execution_run_id", (this.firstExecutionRunId)); - return proto.build(); - } - - public static SignalWithStartWorkflowResponse fromProto( - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto, - io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type modelType) { - Builder builder = SignalWithStartWorkflowResponse.newBuilder(); - if (true) - builder.setRunId( - (String) io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "run_id")); - if (true) - builder.setStarted( - (Boolean) io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "started")); - if (true) - builder.setFirstExecutionRunId( - (String) - io.temporal.nexus.system.workflowservice.NexgenRuntime.get( - proto, "first_execution_run_id")); - return builder.build(); - } - - public static final class Converter - implements io.temporal.common.converter.TransferTypeConverter< - SignalWithStartWorkflowResponse> { - public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { - return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.class; - } - - public Object toTransferType(SignalWithStartWorkflowResponse value) { - return value == null - ? null - : value.toProto(io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter()); - } - - public SignalWithStartWorkflowResponse fromTransferType( - Object value, java.lang.reflect.Type valueType) { - return value == null - ? null - : fromProto( - (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value, - io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter(), - valueType); - } - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusOperations.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusOperations.java deleted file mode 100644 index 81bd118d68..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusOperations.java +++ /dev/null @@ -1,40 +0,0 @@ -// Generated by nexgen v0.2.9. DO NOT EDIT! -package io.temporal.nexus.system.workflowservice; - -/** Generated operation dispatch and serialization context acquisition. */ -@SuppressWarnings({"unchecked", "rawtypes"}) -public final class SystemNexusOperations { - private SystemNexusOperations() {} - - public static - io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput< - R> - execute( - SystemNexusWorkflowOutboundInterceptor interceptor, - io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor - .ExecuteNexusOperationInput< - R> - input) { - if ("temporal.api.workflowservice.v1.WorkflowService".equals(input.getService()) - && "SignalWithStartWorkflowExecution".equals(input.getOperation())) - return (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor - .ExecuteNexusOperationOutput< - R>) - interceptor.executeSignalWithStartWorkflow( - (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor - .ExecuteNexusOperationInput) - input); - throw new IllegalArgumentException( - "Unsupported system Nexus operation: " + input.getService() + "/" + input.getOperation()); - } - - public static io.temporal.payload.context.SerializationContext serializationContext( - String service, String operation, Object request) { - if ("temporal.api.workflowservice.v1.WorkflowService".equals(service) - && "SignalWithStartWorkflowExecution".equals(operation)) - return io.temporal.internal.nexus.system.TemporalModelConverters - .signalWithStartWorkflowSerializationContext( - (io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest) request); - return null; - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusWorkflowOutboundInterceptor.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusWorkflowOutboundInterceptor.java deleted file mode 100644 index cfe819438e..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/SystemNexusWorkflowOutboundInterceptor.java +++ /dev/null @@ -1,41 +0,0 @@ -// Generated by nexgen v0.2.9. DO NOT EDIT! -package io.temporal.nexus.system.workflowservice; - -/** Generated typed system Nexus hooks. */ -public interface SystemNexusWorkflowOutboundInterceptor { - - io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput< - R> - executeNexusOperation( - io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor - .ExecuteNexusOperationInput< - R> - input); - - default io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor - .ExecuteNexusOperationOutput< - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse> - executeSignalWithStartWorkflow( - io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor - .ExecuteNexusOperationInput< - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse> - input) { - return executeNexusOperation(input); - } - - abstract class Base implements SystemNexusWorkflowOutboundInterceptor { - protected abstract SystemNexusWorkflowOutboundInterceptor nextSystemNexusInterceptor(); - - @Override - public io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor - .ExecuteNexusOperationOutput< - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse> - executeSignalWithStartWorkflow( - io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor - .ExecuteNexusOperationInput< - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse> - input) { - return nextSystemNexusInterceptor().executeSignalWithStartWorkflow(input); - } - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/UserMetadata.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/UserMetadata.java deleted file mode 100644 index 0257cbf762..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/UserMetadata.java +++ /dev/null @@ -1,132 +0,0 @@ -// Generated by nexgen v0.2.9. DO NOT EDIT! -package io.temporal.nexus.system.workflowservice; - -@io.temporal.common.converter.TransferTypeConvertible(UserMetadata.Converter.class) -@SuppressWarnings({"unchecked", "rawtypes"}) -public final class UserMetadata { - /** - * Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be - * in single-line Temporal Markdown format. - */ - private final Object staticSummary; - - /** - * General fixed details for the workflow execution that may appear in UI and CLI. This can be in - * Temporal Markdown format and can span multiple lines. This value is fixed on the workflow - * execution and cannot be updated. - */ - private final Object staticDetails; - - @com.fasterxml.jackson.annotation.JsonCreator - public UserMetadata( - @com.fasterxml.jackson.annotation.JsonProperty("staticSummary") Object staticSummary, - @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") Object staticDetails) { - this.staticSummary = staticSummary; - this.staticDetails = staticDetails; - } - - public Object getStaticSummary() { - return staticSummary; - } - - public Object getStaticDetails() { - return staticDetails; - } - - public Builder toBuilder() { - return newBuilder(this); - } - - public static Builder newBuilder(UserMetadata value) { - return new Builder(value); - } - - public static Builder newBuilder() { - return new Builder(); - } - - public static final class Builder { - private Builder() {} - - private Builder(UserMetadata value) { - if (value == null) return; - this.staticSummary = value.staticSummary; - this.staticDetails = value.staticDetails; - } - - private Object staticSummary = null; - - public Builder setStaticSummary(Object value) { - this.staticSummary = value; - return this; - } - - private Object staticDetails = null; - - public Builder setStaticDetails(Object value) { - this.staticDetails = value; - return this; - } - - public UserMetadata build() { - return new UserMetadata(staticSummary, staticDetails); - } - } - - public io.temporal.api.sdk.v1.UserMetadata toProto( - io.temporal.common.converter.DataConverter converter) { - io.temporal.api.sdk.v1.UserMetadata.Builder proto = - io.temporal.api.sdk.v1.UserMetadata.newBuilder(); - if (this.staticSummary != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "summary", converter.toPayload((this.staticSummary)).get()); - if (this.staticDetails != null) - io.temporal.nexus.system.workflowservice.NexgenRuntime.set( - proto, "details", converter.toPayload((this.staticDetails)).get()); - return proto.build(); - } - - public static UserMetadata fromProto( - io.temporal.api.sdk.v1.UserMetadata proto, - io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type modelType) { - Builder builder = UserMetadata.newBuilder(); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "summary")) - builder.setStaticSummary( - (Object) - io.temporal.nexus.system.workflowservice.NexgenRuntime.decode( - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "summary"), - converter, - Object.class)); - if (io.temporal.nexus.system.workflowservice.NexgenRuntime.has(proto, "details")) - builder.setStaticDetails( - (Object) - io.temporal.nexus.system.workflowservice.NexgenRuntime.decode( - io.temporal.nexus.system.workflowservice.NexgenRuntime.get(proto, "details"), - converter, - Object.class)); - return builder.build(); - } - - public static final class Converter - implements io.temporal.common.converter.TransferTypeConverter { - public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { - return io.temporal.api.sdk.v1.UserMetadata.class; - } - - public Object toTransferType(UserMetadata value) { - return value == null - ? null - : value.toProto(io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter()); - } - - public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueType) { - return value == null - ? null - : fromProto( - (io.temporal.api.sdk.v1.UserMetadata) value, - io.temporal.nexus.system.workflowservice.NexgenRuntime.dataConverter(), - valueType); - } - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowService.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowService.java deleted file mode 100644 index 5c551ad2ed..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowService.java +++ /dev/null @@ -1,9 +0,0 @@ -// Generated by nexgen v0.2.9. DO NOT EDIT! -package io.temporal.nexus.system.workflowservice; - -@io.nexusrpc.Service(name = "temporal.api.workflowservice.v1.WorkflowService") -public interface WorkflowService { - @io.nexusrpc.Operation(name = "SignalWithStartWorkflowExecution") - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse signalWithStartWorkflow( - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest request); -} diff --git a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowServiceOperations.java b/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowServiceOperations.java deleted file mode 100644 index 73cb18141f..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/nexus/system/workflowservice/WorkflowServiceOperations.java +++ /dev/null @@ -1,38 +0,0 @@ -// Generated by nexgen v0.2.9. DO NOT EDIT! -package io.temporal.nexus.system.workflowservice; - -@SuppressWarnings({"unchecked", "rawtypes"}) -public final class WorkflowServiceOperations { - private WorkflowServiceOperations() {} - - public static io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse - signalWithStartWorkflow( - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest request) { - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse result = - (io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse) - io.temporal.workflow.Workflow.newUntypedNexusServiceStub( - "temporal.api.workflowservice.v1.WorkflowService", - io.temporal.workflow.NexusServiceOptions.newBuilder() - .setEndpoint("__temporal_system") - .build()) - .execute( - "SignalWithStartWorkflowExecution", - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse.class, - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse.class, - request); - return result; - } - - public static io.temporal.payload.context.SerializationContext - signalWithStartWorkflowSerializationContext( - io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest request) { - return io.temporal.internal.nexus.system.TemporalModelConverters - .signalWithStartWorkflowSerializationContext(request); - } - - public static T withDataConverter( - io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { - return io.temporal.nexus.system.workflowservice.NexgenRuntime.withDataConverter( - converter, action); - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowOptions.java b/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowOptions.java deleted file mode 100644 index edaf1495ae..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowOptions.java +++ /dev/null @@ -1,226 +0,0 @@ -package io.temporal.workflow; - -import io.temporal.client.WorkflowOptions; -import io.temporal.common.Experimental; - -/** Options for signaling an external workflow, starting it if necessary. */ -@Experimental -public final class SignalWithStartWorkflowOptions { - private final WorkflowOptions options; - - private SignalWithStartWorkflowOptions(WorkflowOptions options) { - this.options = options; - } - - public static Builder newBuilder() { - return new Builder(null); - } - - public static Builder newBuilder(SignalWithStartWorkflowOptions options) { - return new Builder(options); - } - - public Builder toBuilder() { - return newBuilder(this); - } - - public String getWorkflowId() { - return options.getWorkflowId(); - } - - public String getTaskQueue() { - return options.getTaskQueue(); - } - - public java.time.Duration getWorkflowExecutionTimeout() { - return options.getWorkflowExecutionTimeout(); - } - - public java.time.Duration getWorkflowRunTimeout() { - return options.getWorkflowRunTimeout(); - } - - public java.time.Duration getWorkflowTaskTimeout() { - return options.getWorkflowTaskTimeout(); - } - - public io.temporal.api.enums.v1.WorkflowIdReusePolicy getWorkflowIdReusePolicy() { - return options.getWorkflowIdReusePolicy(); - } - - public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getWorkflowIdConflictPolicy() { - return options.getWorkflowIdConflictPolicy(); - } - - public io.temporal.common.RetryOptions getRetryOptions() { - return options.getRetryOptions(); - } - - public String getCronSchedule() { - return options.getCronSchedule(); - } - - public java.util.Map getMemo() { - return options.getMemo(); - } - - public io.temporal.common.SearchAttributes getTypedSearchAttributes() { - return options.getTypedSearchAttributes(); - } - - public io.temporal.common.Priority getPriority() { - return options.getPriority(); - } - - public io.temporal.common.VersioningOverride getVersioningOverride() { - return options.getVersioningOverride(); - } - - public java.time.Duration getStartDelay() { - return options.getStartDelay(); - } - - public String getStaticSummary() { - return options.getStaticSummary(); - } - - public String getStaticDetails() { - return options.getStaticDetails(); - } - - public String getRequestId() { - return options.getRequestId(); - } - - public static final class Builder { - private final WorkflowOptions.Builder options; - - private Builder(SignalWithStartWorkflowOptions value) { - options = - value == null ? WorkflowOptions.newBuilder() : WorkflowOptions.newBuilder(value.options); - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setWorkflowId}. */ - public Builder setWorkflowId(String value) { - options.setWorkflowId(value); - return this; - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setTaskQueue}. */ - public Builder setTaskQueue(String value) { - options.setTaskQueue(value); - return this; - } - - /** - * Sets the workflow start option; see {@link - * WorkflowOptions.Builder#setWorkflowExecutionTimeout}. - */ - public Builder setWorkflowExecutionTimeout(java.time.Duration value) { - options.setWorkflowExecutionTimeout(value); - return this; - } - - /** - * Sets the workflow start option; see {@link WorkflowOptions.Builder#setWorkflowRunTimeout}. - */ - public Builder setWorkflowRunTimeout(java.time.Duration value) { - options.setWorkflowRunTimeout(value); - return this; - } - - /** - * Sets the workflow start option; see {@link WorkflowOptions.Builder#setWorkflowTaskTimeout}. - */ - public Builder setWorkflowTaskTimeout(java.time.Duration value) { - options.setWorkflowTaskTimeout(value); - return this; - } - - /** - * Sets the workflow start option; see {@link WorkflowOptions.Builder#setWorkflowIdReusePolicy}. - */ - public Builder setWorkflowIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { - options.setWorkflowIdReusePolicy(value); - return this; - } - - /** - * Sets the workflow start option; see {@link - * WorkflowOptions.Builder#setWorkflowIdConflictPolicy}. - */ - public Builder setWorkflowIdConflictPolicy( - io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { - options.setWorkflowIdConflictPolicy(value); - return this; - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setRetryOptions}. */ - public Builder setRetryOptions(io.temporal.common.RetryOptions value) { - options.setRetryOptions(value); - return this; - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setCronSchedule}. */ - public Builder setCronSchedule(String value) { - options.setCronSchedule(value); - return this; - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setMemo}. */ - public Builder setMemo(java.util.Map value) { - options.setMemo(value); - return this; - } - - /** - * Sets the workflow start option; see {@link WorkflowOptions.Builder#setTypedSearchAttributes}. - */ - public Builder setTypedSearchAttributes(io.temporal.common.SearchAttributes value) { - options.setTypedSearchAttributes(value); - return this; - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setPriority}. */ - public Builder setPriority(io.temporal.common.Priority value) { - options.setPriority(value); - return this; - } - - /** - * Sets the workflow start option; see {@link WorkflowOptions.Builder#setVersioningOverride}. - */ - public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { - options.setVersioningOverride(value); - return this; - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setStartDelay}. */ - public Builder setStartDelay(java.time.Duration value) { - options.setStartDelay(value); - return this; - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setStaticSummary}. */ - public Builder setStaticSummary(String value) { - options.setStaticSummary(value); - return this; - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setStaticDetails}. */ - public Builder setStaticDetails(String value) { - options.setStaticDetails(value); - return this; - } - - /** Sets the workflow start option; see {@link WorkflowOptions.Builder#setRequestId}. */ - public Builder setRequestId(String value) { - options.setRequestId(value); - return this; - } - - public SignalWithStartWorkflowOptions build() { - return new SignalWithStartWorkflowOptions(options.build()); - } - } -} diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowStub.java b/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowStub.java deleted file mode 100644 index 2b294e1ae9..0000000000 --- a/temporal-sdk/src/main/java/io/temporal/workflow/SignalWithStartWorkflowStub.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.temporal.workflow; - -import io.temporal.common.Experimental; -import io.temporal.internal.sync.SignalWithStartWorkflowInvocationHandler; - -/** Untyped workflow-side stub for atomic signal-with-start through system Nexus. */ -@Experimental -public interface SignalWithStartWorkflowStub { - static SignalWithStartWorkflowStub fromTyped(Object stub) { - return SignalWithStartWorkflowInvocationHandler.fromTyped(stub); - } - - String getWorkflowType(); - - SignalWithStartWorkflowOptions getOptions(); - - /** Waits for signal delivery/start, then returns a stub for signaling or cancellation. */ - ExternalWorkflowStub signalWithStart(String signalName, Object[] signalArgs, Object... startArgs); -} diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java b/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java index 3937a85b94..2e77b94081 100644 --- a/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java +++ b/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.java @@ -53,36 +53,9 @@ * * @see io.temporal.workflow */ -public final class Workflow { +public final class Workflow extends WorkflowOperations { public static final int DEFAULT_VERSION = WorkflowInternal.DEFAULT_VERSION; - /** Creates a typed stub whose workflow and signal calls can be captured by signalWithStart. */ - @Experimental - public static T newSignalWithStartWorkflowStub( - Class workflowInterface, SignalWithStartWorkflowOptions options) { - return io.temporal.internal.sync.SignalWithStartWorkflowInvocationHandler.newStub( - workflowInterface, options); - } - - /** Creates an untyped stub for signaling a workflow and starting it if necessary. */ - @Experimental - public static SignalWithStartWorkflowStub newUntypedSignalWithStartWorkflowStub( - String workflowType, SignalWithStartWorkflowOptions options) { - return new io.temporal.internal.sync.SignalWithStartWorkflowStubImpl(workflowType, options); - } - - /** - * Captures a workflow call and signal call on target, then sends one atomic system Nexus - * operation. Returns an external stub after signal delivery/start completes. Use Async.function - * for a Promise. - */ - @Experimental - public static T signalWithStart( - T target, Functions.Proc workflowCall, Functions.Proc signalCall) { - return io.temporal.internal.sync.SignalWithStartWorkflowInvocationHandler.signalWithStart( - target, workflowCall, signalCall); - } - /** * Creates client stub to activities that implement given interface. ` * diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index 08c2012300..797125ced4 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -13,7 +13,12 @@ Regenerate with nex-gen 0.2.9 built with its `advanced` feature: ./gradlew --offline spotlessApply ``` -Generated Java and `system-nexus-roots.txt` are checked in. The manifest derives +Generated Java and `system-nexus-roots.txt` are checked in under +`src/main/generated/io/temporal/workflow`, an isolated main Java source root. +The generator uses `--package-name io.temporal.workflow` and the WIT annotation +`@nexus.operations-class java="WorkflowOperations"`. `Workflow` extends this +generated base once; additional operations require no handwritten facade methods. +The generated request builders are directly usable from the workflow package. The manifest derives from operation input/output protobuf transfer types. The service client's Java payload visitor generator consumes it, including payload-free response roots, without depending on compiled SDK classes. diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md index a69b5e6ed8..068a9d73ce 100644 --- a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -1,35 +1,34 @@ # Signal with start inside workflows -Signal with start atomically signals an external workflow, starting it when -necessary. It uses the Temporal system Nexus endpoint and requires a server -that supports that service. +The generated workflow API atomically signals an external workflow, starting it +when necessary. It requires a server supporting the system workflow service. ```java -TargetWorkflow target = Workflow.newSignalWithStartWorkflowStub( - TargetWorkflow.class, - SignalWithStartWorkflowOptions.newBuilder() - .setWorkflowId("target") +ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( + SignalWithStartWorkflowRequest.newBuilder() + .setWorkflow("TargetWorkflow") + .setSignal("notify") + .setId("target") .setTaskQueue("target-queue") + .setArgs(Collections.singletonList(input)) + .setSignalArgs(Collections.singletonList(signal)) .build()); -TargetWorkflow external = Workflow.signalWithStart( - target, - () -> target.run(input), - () -> target.notifySignal(signal)); ``` -The two lambdas capture exactly one workflow call and one signal call. Both -must use `target`; capture does not start the workflow. The operation waits for -signal delivery/start to complete and returns an external workflow stub for -signaling and cancellation. It does not wait for the target workflow's result. -Use `Async.function(() -> Workflow.signalWithStart(...))` for a `Promise`. +Import `Workflow`, `SignalWithStartWorkflowRequest`, and `ExternalWorkflowStub` +from `io.temporal.workflow`. The generated request builder contains the API's +options, including timeouts, retry policy, memo, conflict policy, and flattened +static summary/details setters. Workflow ID and task queue are explicit request +fields. Namespace defaults to the caller's namespace. Request ID is omitted: +the system service manages it. -An untyped equivalent is available through -`Workflow.newUntypedSignalWithStartWorkflowStub`. Options default the task queue -to the caller's queue and generate a deterministic workflow ID when omitted. -The destination namespace is the caller's namespace. Serialization uses that -namespace and the destination workflow ID for nested payloads, codecs, and -failure conversion; the system protobuf envelope remains server-readable. +The call returns after signal delivery/start completes. The returned external +stub supports further signals and cancellation. Use +`Async.function(Workflow::signalWithStartWorkflow, request)` for a promise. -Generated outbound interceptor hooks expose the system operation independently -of ordinary Nexus operations. Existing outbound interceptor implementations -remain compatible through default methods and the forwarding base class. +`Workflow` inherits generated operations from `WorkflowOperations`. New WIT +operations become available after regeneration, without adding handwritten +options, capture proxies, stubs, or facade methods. The output transform, request +fields, and serialization-context hook are declared in WIT. The converter uses +the destination namespace and workflow ID for nested payloads, codecs, and +failures; the outer system envelope remains server-readable. diff --git a/temporal-sdk/src/main/nexus/workflow-service.wit b/temporal-sdk/src/main/nexus/workflow-service.wit index 685498ac58..eab3503f3f 100644 --- a/temporal-sdk/src/main/nexus/workflow-service.wit +++ b/temporal-sdk/src/main/nexus/workflow-service.wit @@ -7,7 +7,7 @@ world system { /// @nexus.endpoint "__temporal_system" /// @nexus.service-name "temporal.api.workflowservice.v1.WorkflowService" /// @nexus.namespace dotnet="Temporalio.Workflows" -/// @nexus.operations-class dotnet="Workflow" +/// @nexus.operations-class java="WorkflowOperations" dotnet="Workflow" /// @nexus.delay-load-temporalio-workflow /// @nexus.experimental interface workflow-service { @@ -61,8 +61,8 @@ interface workflow-service { task-timeout: option, /// @nexus.omit identity: placeholder, - /// @nexus.doc "Request ID used to deduplicate workflow start requests." - request-id: option, + /// @nexus.omit + request-id: placeholder, /// @nexus.doc "Behavior when a closed workflow with the same ID exists. Default is allow-duplicate." /// @nexus.proto-field "workflow_id_reuse_policy" /// @nexus.default "allow-duplicate" @@ -113,6 +113,8 @@ interface workflow-service { /// "Signal a workflow, starting it first if needed." /// returns="A workflow handle to the started workflow." /// @nexus.output-transform + /// java-type="io.temporal.workflow.ExternalWorkflowStub" + /// java="io.temporal.workflow.Workflow.newUntypedExternalWorkflowStub(io.temporal.api.common.v1.WorkflowExecution.newBuilder().setWorkflowId(request.getId()).setRunId(result.getRunId() == null ? \"\" : result.getRunId()).build())" /// python-type="temporalio.workflow.ExternalWorkflowHandle[WorkflowResult]" /// python="temporalio.workflow.get_external_workflow_handle(request.id, run_id=result.run_id)" /// typescript-type="workflow.ExternalWorkflowHandle" diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java index 2639bea4a7..1d16ba755d 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java @@ -7,10 +7,10 @@ import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest; import io.temporal.common.converter.*; import io.temporal.internal.payload.visitor.SystemNexusPayloads; -import io.temporal.nexus.system.workflowservice.*; import io.temporal.payload.codec.PayloadCodec; import io.temporal.payload.context.SerializationContext; import io.temporal.payload.context.WorkflowSerializationContext; +import io.temporal.workflow.*; import java.util.*; import java.util.stream.Collectors; import javax.annotation.Nonnull; @@ -37,6 +37,29 @@ private static SignalWithStartWorkflowRequest request(String id) { .build(); } + @Test + public void decodesUnmarkedServerResponse() { + Payload response = + SystemNexusPayloads.pack( + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse + .newBuilder() + .setRunId("run") + .setStarted(true) + .build()) + .toBuilder() + .removeMetadata("__temporal_system_payload") + .build(); + assertFalse(SystemNexusPayloads.isSystemPayload(response)); + SignalWithStartWorkflowResponse decoded = + new SystemNexusDataConverter(DefaultDataConverter.STANDARD_INSTANCE) + .fromPayload( + response, + SignalWithStartWorkflowResponse.class, + SignalWithStartWorkflowResponse.class); + assertEquals("run", decoded.getRunId()); + assertEquals(Boolean.TRUE, decoded.getStarted()); + } + @Test public void nestedPayloadsUseDestinationContextAndOuterEnvelopeBypassesCodecs() throws Exception { SignalWithStartWorkflowRequest request = request("target"); @@ -56,6 +79,7 @@ public void nestedPayloadsUseDestinationContextAndOuterEnvelopeBypassesCodecs() assertFalse(encoded.getMetadataMap().containsKey("test-context")); SignalWithStartWorkflowExecutionRequest wire = SignalWithStartWorkflowExecutionRequest.parseFrom(encoded.getData()); + assertEquals("", wire.getRequestId()); assertEquals( "target", wire.getInput().getPayloads(0).getMetadataOrThrow("test-context").toStringUtf8()); assertEquals( diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java index 8d48a3364e..d03bb45a9c 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -3,11 +3,11 @@ import static org.junit.Assert.*; import io.temporal.common.interceptors.*; -import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowRequest; -import io.temporal.nexus.system.workflowservice.SignalWithStartWorkflowResponse; import io.temporal.testing.internal.SDKTestWorkflowRule; import io.temporal.worker.WorkerFactoryOptions; import io.temporal.workflow.*; +import io.temporal.workflow.SignalWithStartWorkflowRequest; +import io.temporal.workflow.SignalWithStartWorkflowResponse; import org.junit.Rule; import org.junit.Test; @@ -61,21 +61,8 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { .build(); @Test - public void typedUntypedAndAsyncCallsReturnExternalStubs() { - assertEquals( - "typed:run,untyped:run,async:run", rule.newWorkflowStubTimeoutOptions(Caller.class).run()); - } - - @WorkflowInterface - public interface Target { - @WorkflowMethod(name = "Target") - String run(String value); - - @SignalMethod(name = "notify") - void notifySignal(String value); - - @QueryMethod - String query(); + public void generatedWorkflowMethodsReturnExternalStubs() { + assertEquals("sync:run,async:run", rule.newWorkflowStubTimeoutOptions(Caller.class).run()); } @WorkflowInterface @@ -87,64 +74,27 @@ public interface Caller { public static class CallerImpl implements Caller { @Override public String run() { - SignalWithStartWorkflowOptions options = - SignalWithStartWorkflowOptions.newBuilder() - .setWorkflowId("typed") + SignalWithStartWorkflowRequest request = + SignalWithStartWorkflowRequest.newBuilder() + .setWorkflow("Target") + .setSignal("notify") + .setId("sync") .setTaskQueue("queue") + .setArgs(java.util.Collections.singletonList("input")) + .setSignalArgs(java.util.Collections.singletonList("signal")) .build(); - Target target = Workflow.newSignalWithStartWorkflowStub(Target.class, options); - assertThrows( - IllegalArgumentException.class, - () -> - Workflow.signalWithStart( - target, - () -> { - target.run("input"); - target.run("duplicate"); - }, - () -> target.notifySignal("signal"))); - assertThrows( - IllegalArgumentException.class, - () -> - Workflow.signalWithStart( - target, () -> target.query(), () -> target.notifySignal("signal"))); - Target other = Workflow.newSignalWithStartWorkflowStub(Target.class, options); - assertThrows( - IllegalStateException.class, - () -> - Workflow.signalWithStart( - target, () -> other.run("input"), () -> target.notifySignal("signal"))); - Target external = - Workflow.signalWithStart( - target, () -> target.run("input"), () -> target.notifySignal("signal")); - String typed = - Workflow.getWorkflowExecution(external).get().getWorkflowId() - + ":" - + Workflow.getWorkflowExecution(external).get().getRunId(); - ExternalWorkflowStub untyped = - Workflow.newUntypedSignalWithStartWorkflowStub( - "Target", options.toBuilder().setWorkflowId("untyped").build()) - .signalWithStart("notify", new Object[] {"signal"}, "input"); - Target asyncTarget = - Workflow.newSignalWithStartWorkflowStub( - Target.class, options.toBuilder().setWorkflowId("async").build()); - Target async = + ExternalWorkflowStub sync = Workflow.signalWithStartWorkflow(request); + ExternalWorkflowStub async = Async.function( - () -> - Workflow.signalWithStart( - asyncTarget, - () -> asyncTarget.run("input"), - () -> asyncTarget.notifySignal("signal"))) + Workflow::signalWithStartWorkflow, request.toBuilder().setId("async").build()) .get(); - return typed - + "," - + untyped.getExecution().getWorkflowId() + return sync.getExecution().getWorkflowId() + ":" - + untyped.getExecution().getRunId() + + sync.getExecution().getRunId() + "," - + Workflow.getWorkflowExecution(async).get().getWorkflowId() + + async.getExecution().getWorkflowId() + ":" - + Workflow.getWorkflowExecution(async).get().getRunId(); + + async.getExecution().getRunId(); } } } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java index 2362da34bf..ec54c2e571 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -74,17 +74,26 @@ public static class CallerImpl implements Caller { @Override public String run() { String id = Workflow.getInfo().getWorkflowId() + "-target"; - SignalWithStartWorkflowOptions options = - SignalWithStartWorkflowOptions.newBuilder() - .setWorkflowId(id) - .setWorkflowIdConflictPolicy( + SignalWithStartWorkflowRequest request = + SignalWithStartWorkflowRequest.newBuilder() + .setWorkflow("SystemSignalTarget") + .setSignal("notifySignal") + .setId(id) + .setTaskQueue(Workflow.getInfo().getTaskQueue()) + .setIdConflictPolicy( WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) + .setArgs(java.util.Collections.singletonList("start")) + .setSignalArgs(java.util.Collections.singletonList("first")) .build(); - Target target = Workflow.newSignalWithStartWorkflowStub(Target.class, options); - Workflow.signalWithStart( - target, () -> target.run("start"), () -> target.notifySignal("first")); - Workflow.signalWithStart( - target, () -> target.run("ignored"), () -> target.notifySignal("second")); + ExternalWorkflowStub external = Workflow.signalWithStartWorkflow(request); + assertEquals(id, external.getExecution().getWorkflowId()); + Async.function( + Workflow::signalWithStartWorkflow, + request.toBuilder() + .setArgs(java.util.Collections.singletonList("ignored")) + .setSignalArgs(java.util.Collections.singletonList("second")) + .build()) + .get(); return id; } } diff --git a/temporal-serviceclient/build.gradle b/temporal-serviceclient/build.gradle index 3b4fa3b326..e653778ef7 100644 --- a/temporal-serviceclient/build.gradle +++ b/temporal-serviceclient/build.gradle @@ -159,7 +159,7 @@ def generatePayloadVisitor = tasks.register('generatePayloadVisitor', JavaExec) mustRunAfter ':temporal-sdk:generateNexusSystemApi' classpath = sourceSets.payloadGenerators.runtimeClasspath mainClass = 'io.temporal.internal.payload.visitor.gen.PayloadVisitorGenerator' - def systemRoots = project(':temporal-sdk').file('src/main/java/io/temporal/nexus/system/workflowservice/system-nexus-roots.txt') + def systemRoots = project(':temporal-sdk').file('src/main/generated/io/temporal/workflow/system-nexus-roots.txt') args apiDescriptorSet.get().asFile.absolutePath, generatedPayloadVisitorDir.get().asFile.absolutePath, systemRoots.absolutePath inputs.file(systemRoots) inputs.file(apiDescriptorSet) diff --git a/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java index 9ca978cf68..03eed8a3c6 100644 --- a/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java +++ b/temporal-serviceclient/src/main/java/io/temporal/internal/payload/visitor/SystemNexusPayloads.java @@ -28,7 +28,9 @@ public static Payload pack(Message message) { } public static Message.Builder unpack(Payload payload) { - if (!isSystemPayload(payload) || !ENCODING.equals(payload.getMetadataMap().get("encoding"))) { + // The marker controls generic visitation. Server responses use the same binary envelope + // without the marker and are decoded in the system operation's known converter scope. + if (!ENCODING.equals(payload.getMetadataMap().get("encoding"))) { throw new VisitorException("Invalid Temporal system payload encoding"); } ByteString type = payload.getMetadataMap().get("messageType"); From cd2feadb368f2e2715be061eb6e8037397f4b0fa Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Mon, 19 Oct 2026 13:02:03 -0700 Subject: [PATCH 04/17] Use the shared multi-language workflow service WIT verbatim --- .../SignalWithStartWorkflowRequest.java | 20 +++-- .../SignalWithStartWorkflowResponse.java | 21 +++--- .../io/temporal/workflow/UserMetadata.java | 3 + temporal-sdk/src/main/nexus/README.md | 9 ++- .../nexus/deps/nexus-temporal-types/model.wit | 75 ++++++++++++++++--- .../src/main/nexus/workflow-service.wit | 40 +++++++--- 6 files changed, 128 insertions(+), 40 deletions(-) diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java index 179a2ef2c1..15ee3483c1 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java @@ -13,7 +13,7 @@ public final class SignalWithStartWorkflowRequest { */ private final java.util.List args; /** - * Unique identifier for the workflow execution. + * Unique identifier for the workflow execution. Must be nonempty. */ private final String id; /** @@ -26,15 +26,16 @@ public final class SignalWithStartWorkflowRequest { */ private final java.util.List signalArgs; /** - * Total workflow execution timeout, including retries and continue-as-new. + * Total workflow execution timeout, including retries and continue-as-new. Defaults + * to unlimited. */ private final java.time.Duration executionTimeout; /** - * Timeout of a single workflow run. + * Timeout of a single workflow run. Defaults to the workflow execution timeout. */ private final java.time.Duration runTimeout; /** - * Timeout of a single workflow task. + * Timeout of a single workflow task. Defaults to 10 seconds. */ private final java.time.Duration taskTimeout; /** @@ -45,7 +46,7 @@ public final class SignalWithStartWorkflowRequest { /** * Behavior when a workflow is currently running with the same ID. Set to use-existing * for idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is - * terminate-if-running. + * terminate-if-running. Defaults to use-existing. */ private final io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy; /** @@ -78,8 +79,17 @@ public final class SignalWithStartWorkflowRequest { * cron-schedule. */ private final java.time.Duration startDelay; + /** + * Static metadata for the workflow execution. + */ private final io.temporal.workflow.UserMetadata userMetadata; + /** + * Namespace of the workflow execution. + */ private final String namespace; + /** + * Headers for the request. + */ private final java.util.Map headers; @com.fasterxml.jackson.annotation.JsonCreator public SignalWithStartWorkflowRequest(@com.fasterxml.jackson.annotation.JsonProperty("workflow") String workflow, @com.fasterxml.jackson.annotation.JsonProperty("args") java.util.List args, @com.fasterxml.jackson.annotation.JsonProperty("id") String id, @com.fasterxml.jackson.annotation.JsonProperty("taskQueue") String taskQueue, @com.fasterxml.jackson.annotation.JsonProperty("signal") String signal, @com.fasterxml.jackson.annotation.JsonProperty("signalArgs") java.util.List signalArgs, @com.fasterxml.jackson.annotation.JsonProperty("executionTimeout") java.time.Duration executionTimeout, @com.fasterxml.jackson.annotation.JsonProperty("runTimeout") java.time.Duration runTimeout, @com.fasterxml.jackson.annotation.JsonProperty("taskTimeout") java.time.Duration taskTimeout, @com.fasterxml.jackson.annotation.JsonProperty("idReusePolicy") io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy, @com.fasterxml.jackson.annotation.JsonProperty("idConflictPolicy") io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy, @com.fasterxml.jackson.annotation.JsonProperty("retryPolicy") io.temporal.common.RetryOptions retryPolicy, @com.fasterxml.jackson.annotation.JsonProperty("cronSchedule") String cronSchedule, @com.fasterxml.jackson.annotation.JsonProperty("memo") java.util.Map memo, @com.fasterxml.jackson.annotation.JsonProperty("searchAttributes") io.temporal.common.SearchAttributes searchAttributes, @com.fasterxml.jackson.annotation.JsonProperty("priority") io.temporal.common.Priority priority, @com.fasterxml.jackson.annotation.JsonProperty("versioningOverride") io.temporal.common.VersioningOverride versioningOverride, @com.fasterxml.jackson.annotation.JsonProperty("startDelay") java.time.Duration startDelay, @com.fasterxml.jackson.annotation.JsonProperty("userMetadata") io.temporal.workflow.UserMetadata userMetadata, @com.fasterxml.jackson.annotation.JsonProperty("namespace") String namespace, @com.fasterxml.jackson.annotation.JsonProperty("headers") java.util.Map headers) { diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java index 619c4330e2..84a3a5250e 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java @@ -1,21 +1,27 @@ // Generated by nexgen v0.2.9. DO NOT EDIT! package io.temporal.workflow; +/** + * Result of signaling a workflow and starting it if needed. + */ @io.temporal.common.converter.TransferTypeConvertible(SignalWithStartWorkflowResponse.Converter.class) @SuppressWarnings({"unchecked", "rawtypes"}) public final class SignalWithStartWorkflowResponse { + /** + * Run ID of the started workflow. + */ private final String runId; + /** + * Whether the workflow was started. + */ private final Boolean started; - private final String firstExecutionRunId; @com.fasterxml.jackson.annotation.JsonCreator - public SignalWithStartWorkflowResponse(@com.fasterxml.jackson.annotation.JsonProperty("runId") String runId, @com.fasterxml.jackson.annotation.JsonProperty("started") Boolean started, @com.fasterxml.jackson.annotation.JsonProperty("firstExecutionRunId") String firstExecutionRunId) { + public SignalWithStartWorkflowResponse(@com.fasterxml.jackson.annotation.JsonProperty("runId") String runId, @com.fasterxml.jackson.annotation.JsonProperty("started") Boolean started) { this.runId = runId; this.started = started; - this.firstExecutionRunId = firstExecutionRunId; } public String getRunId() { return runId; } public Boolean getStarted() { return started; } - public String getFirstExecutionRunId() { return firstExecutionRunId; } public Builder toBuilder() { return newBuilder(this); } public static Builder newBuilder(SignalWithStartWorkflowResponse value) { return new Builder(value); } public static Builder newBuilder() { return new Builder(); } @@ -25,28 +31,23 @@ private Builder(SignalWithStartWorkflowResponse value) { if (value == null) return; this.runId = value.runId; this.started = value.started; - this.firstExecutionRunId = value.firstExecutionRunId; } private String runId = null; public Builder setRunId(String value) { this.runId = value; return this; } private Boolean started = null; public Builder setStarted(Boolean value) { this.started = value; return this; } - private String firstExecutionRunId = ""; - public Builder setFirstExecutionRunId(String value) { this.firstExecutionRunId = value; return this; } - public SignalWithStartWorkflowResponse build() { return new SignalWithStartWorkflowResponse(runId, started, firstExecutionRunId); } + public SignalWithStartWorkflowResponse build() { return new SignalWithStartWorkflowResponse(runId, started); } } public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto(io.temporal.common.converter.DataConverter converter) { io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); if (this.runId != null) io.temporal.workflow.NexgenRuntime.set(proto, "run_id", (this.runId)); if (this.started != null) io.temporal.workflow.NexgenRuntime.set(proto, "started", (this.started)); - if (this.firstExecutionRunId != null) io.temporal.workflow.NexgenRuntime.set(proto, "first_execution_run_id", (this.firstExecutionRunId)); return proto.build(); } public static SignalWithStartWorkflowResponse fromProto(io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { Builder builder = SignalWithStartWorkflowResponse.newBuilder(); if (true) builder.setRunId((String) io.temporal.workflow.NexgenRuntime.get(proto, "run_id")); if (true) builder.setStarted((Boolean) io.temporal.workflow.NexgenRuntime.get(proto, "started")); - if (true) builder.setFirstExecutionRunId((String) io.temporal.workflow.NexgenRuntime.get(proto, "first_execution_run_id")); return builder.build(); } public static final class Converter implements io.temporal.common.converter.TransferTypeConverter { diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java index c8aebb2e33..ffdbc12b34 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java @@ -1,6 +1,9 @@ // Generated by nexgen v0.2.9. DO NOT EDIT! package io.temporal.workflow; +/** + * Static metadata for a workflow execution. + */ @io.temporal.common.converter.TransferTypeConvertible(UserMetadata.Converter.class) @SuppressWarnings({"unchecked", "rawtypes"}) public final class UserMetadata { diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index 797125ced4..2a1cbd3c4a 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -1,8 +1,11 @@ # System Nexus bindings -The WIT definitions here describe the workflow-facing Java models for the -vendored workflow service. They retain the upstream wire schema and add Java -native type and serialization context annotations. Protobuf descriptors from +The WIT definitions here are a temporary copy of the shared multi-language +definitions in nex-gen's `advanced/samples/inputs/workflow-service.wit` and +`deps/nexus-temporal-types/model.wit`. Keep the copies identical; Java directives +belong in the shared source alongside the other languages. The SDK will +eventually consume these definitions from the API repo instead. Protobuf +descriptors from `temporal-serviceclient:generateProto` validate the mappings during generation. Regenerate with nex-gen 0.2.9 built with its `advanced` feature: diff --git a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit index 5d7d693107..5a61e9de2d 100644 --- a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit +++ b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit @@ -9,26 +9,48 @@ interface model { /// java="Object" /// python="typing.Any" /// typescript="common.Payload" + /// go="any" /// dotnet="object?" + /// dotnet-from="ProtoExtensions.FromPayload" /// dotnet-to="ProtoExtensions.ToPayload" /// typescript-import="@temporalio/common" type payload = placeholder; /// @nexus.proto "temporal.api.common.v1.Payloads" /// typescript-import="@temporalio/proto" - /// @nexus.type dotnet="IReadOnlyCollection" dotnet-to="ProtoExtensions.ToPayloads" + /// @nexus.type /// java="java.util.List" + /// go="[]any" + /// dotnet="IReadOnlyCollection" + /// dotnet-from="ProtoExtensions.FromPayloads" + /// dotnet-to="ProtoExtensions.ToPayloads" type payloads = list; + /// Temporal failure represented by the target SDK's native exception/error type. + /// The SDK failure converter owns the recursive cause and failure-info structure. + /// @nexus.proto "temporal.api.failure.v1.Failure" typescript-import="@temporalio/proto" + /// @nexus.type + /// java="RuntimeException" + /// java-from="failureFromProto" + /// java-to="failureToProto" + /// python="BaseException" + /// typescript="Error" + /// go="error" + /// dotnet="System.Exception" + /// dotnet-from="ProtoExtensions.FromFailureProto" + /// dotnet-to="ProtoExtensions.ToFailureProto" + type failure = placeholder; + /// Callable result annotation for workflow functions. /// @nexus.type /// python="collections.abc.Awaitable[WorkflowResult]" /// typescript="Promise" + /// go="any" /// dotnet="System.Threading.Tasks.Task" type workflow-result = placeholder; /// Receiver/context argument for workflow callable method forms. - /// @nexus.type python="typing.Any" typescript="any" dotnet="object" + /// @nexus.type python="typing.Any" typescript="any" go="go.temporal.io/sdk/workflow:workflow.Context" dotnet="object" type callable-prefix = placeholder; /// @nexus.function-args @@ -38,7 +60,7 @@ interface model { workflow-call: async func(callable-prefix: callable-prefix, args: payloads) -> workflow-result; /// Callable result annotation for signal functions. - /// @nexus.type python="None | collections.abc.Awaitable[None]" typescript="void" dotnet="void" + /// @nexus.type python="None | collections.abc.Awaitable[None]" typescript="void" go="any" dotnet="void" type signal-result = placeholder; /// @nexus.function-args @@ -54,7 +76,9 @@ interface model { /// java-to="workflowTypeToProto" /// python="str" /// typescript="string" + /// go="string" /// dotnet="string" + /// dotnet-from="ProtoExtensions.FromWorkflowTypeProto" /// dotnet-to="ProtoExtensions.ToWorkflowTypeProto" type workflow-type = placeholder; @@ -64,6 +88,7 @@ interface model { /// args-field="input" /// result-type-parameter="WorkflowResult" /// alternate-type="workflow-type" + /// go-name-extractor="WorkflowFunctionName" /// dotnet-name-extractor="TemporalFunctionNames.WorkflowName" /// dotnet-call-extractor="TemporalFunctionNames.ExtractCall" /// @nexus.add-rpc-compatible-with "workflow-type" @@ -73,13 +98,15 @@ interface model { /// signature="signal-call" /// args-field="signal-input" /// alternate-type="string" + /// go-value-type="string" + /// go-args-type="any" /// python-converter="signal_function_to_proto" /// typescript-name-extractor="signalFunctionName" /// dotnet-name-extractor="TemporalFunctionNames.SignalName" /// dotnet-call-extractor="TemporalFunctionNames.ExtractCall" - /// typescript-value-type="workflow.SignalDefinition" - /// typescript-args-type="Value extends workflow.SignalDefinition ? Args : never" - /// typescript-import="@temporalio/workflow" + /// typescript-value-type="common.SignalDefinition" + /// typescript-args-type="Value extends common.SignalDefinition ? Args : never" + /// typescript-import="@temporalio/common" /// @nexus.add-rpc-compatible-with "string" type signal-function = placeholder; @@ -90,7 +117,9 @@ interface model { /// java-to="retryPolicyToProto" /// python="temporalio.common.RetryPolicy" /// typescript="common.RetryPolicy" + /// go="go.temporal.io/sdk/temporal.RetryPolicy" /// dotnet="Temporalio.Common.RetryPolicy" + /// dotnet-from="ProtoExtensions.FromRetryPolicyProto" /// typescript-import="@temporalio/common" type retry-policy = placeholder; @@ -101,22 +130,36 @@ interface model { /// java-to="taskQueueToProto" /// python="str" /// typescript="string" + /// go="string" /// dotnet="string" + /// dotnet-from="ProtoExtensions.FromTaskQueueProto" /// dotnet-to="ProtoExtensions.ToTaskQueueProto" type task-queue = placeholder; /// @nexus.proto "temporal.api.common.v1.Memo" typescript-import="@temporalio/proto" - /// @nexus.type python="collections.abc.Mapping[str, typing.Any]" typescript="Record" dotnet="IReadOnlyDictionary" + /// @nexus.type /// java="java.util.Map" /// java-from="memoFromProto" /// java-to="memoToProto" + /// python="collections.abc.Mapping[str, typing.Any]" + /// typescript="Record" + /// go="map[string]any" + /// dotnet="IReadOnlyDictionary" + /// dotnet-from="ProtoExtensions.FromMemoProto" type memo = placeholder; - /// @nexus.proto "temporal.api.common.v1.Header" + /// @nexus.proto "temporal.api.common.v1.Header" typescript-import="@temporalio/proto" /// @nexus.type /// java="java.util.Map" /// java-from="headerFromProto" /// java-to="headerToProto" + /// python="collections.abc.Mapping[str, typing.Any]" + /// typescript="common.Headers" + /// go="map[string]any" + /// dotnet="IReadOnlyDictionary" + /// dotnet-from="ProtoExtensions.FromHeaderProto" + /// dotnet-to="ProtoExtensions.ToHeaderProto" + /// typescript-import="@temporalio/common" type header = placeholder; /// @nexus.proto "temporal.api.common.v1.SearchAttributes" typescript-import="@temporalio/proto" @@ -126,7 +169,9 @@ interface model { /// java-to="searchAttributesToProto" /// python="temporalio.common.TypedSearchAttributes" /// typescript="common.TypedSearchAttributes" + /// go="go.temporal.io/sdk/temporal.SearchAttributes" /// dotnet="Temporalio.Common.SearchAttributeCollection" + /// dotnet-from="ProtoExtensions.FromSearchAttributesProto" /// typescript-import="@temporalio/common" type search-attributes = placeholder; @@ -137,7 +182,9 @@ interface model { /// java-to="priorityToProto" /// python="temporalio.common.Priority" /// typescript="common.Priority" + /// go="go.temporal.io/sdk/temporal.Priority" /// dotnet="Temporalio.Common.Priority" + /// dotnet-from="ProtoExtensions.FromPriorityProto" /// typescript-import="@temporalio/common" type priority = placeholder; @@ -148,7 +195,9 @@ interface model { /// java-to="versioningOverrideToProto" /// python="temporalio.common.VersioningOverride" /// typescript="common.VersioningOverride" + /// go="go.temporal.io/sdk/client.VersioningOverride" /// dotnet="Temporalio.Common.VersioningOverride" + /// dotnet-from="ProtoExtensions.FromVersioningOverrideProto" /// typescript-import="@temporalio/common" type versioning-override = placeholder; @@ -159,7 +208,9 @@ interface model { /// java-to="durationToProto" /// python="datetime.timedelta" /// typescript="common.Duration" + /// go="time.Duration" /// dotnet="System.TimeSpan" + /// dotnet-from="ProtoExtensions.FromDurationProto" /// typescript-import="@temporalio/common" type duration = placeholder; @@ -168,6 +219,7 @@ interface model { /// java="io.temporal.api.enums.v1.WorkflowIdReusePolicy" /// python="temporalio.common.WorkflowIDReusePolicy" /// typescript="common.WorkflowIdReusePolicy" + /// go="go.temporal.io/api/enums/v1:enums.WorkflowIdReusePolicy" /// dotnet="Temporalio.Api.Enums.V1.WorkflowIdReusePolicy" /// typescript-import="@temporalio/common" type workflow-id-reuse-policy = placeholder; @@ -177,20 +229,23 @@ interface model { /// java="io.temporal.api.enums.v1.WorkflowIdConflictPolicy" /// python="temporalio.common.WorkflowIDConflictPolicy" /// typescript="common.WorkflowIdConflictPolicy" + /// go="go.temporal.io/api/enums/v1:enums.WorkflowIdConflictPolicy" /// dotnet="Temporalio.Api.Enums.V1.WorkflowIdConflictPolicy" /// typescript-import="@temporalio/common" type workflow-id-conflict-policy = placeholder; + /// @nexus.doc "Static metadata for a workflow execution." /// @nexus.proto "temporal.api.sdk.v1.UserMetadata" typescript-import="@temporalio/proto" /// @nexus.flatten-in-api + /// @nexus.experimental record user-metadata { /// @nexus.doc "Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be in single-line Temporal Markdown format." /// @nexus.proto-field "summary" - /// @nexus.flattened-type python="str" typescript="string" dotnet="string" + /// @nexus.flattened-type python="str" typescript="string" dotnet="string" go="string" static-summary: option, /// @nexus.doc "General fixed details for the workflow execution that may appear in UI and CLI. This can be in Temporal Markdown format and can span multiple lines. This value is fixed on the workflow execution and cannot be updated." /// @nexus.proto-field "details" - /// @nexus.flattened-type python="str" typescript="string" dotnet="string" + /// @nexus.flattened-type python="str" typescript="string" dotnet="string" go="string" static-details: option, } } diff --git a/temporal-sdk/src/main/nexus/workflow-service.wit b/temporal-sdk/src/main/nexus/workflow-service.wit index eab3503f3f..459e4e5d72 100644 --- a/temporal-sdk/src/main/nexus/workflow-service.wit +++ b/temporal-sdk/src/main/nexus/workflow-service.wit @@ -4,10 +4,9 @@ world system { export workflow-service; } -/// @nexus.endpoint "__temporal_system" +/// @nexus.endpoint "temporal-system" go="__temporal_system" python="__temporal_system" java="__temporal_system" /// @nexus.service-name "temporal.api.workflowservice.v1.WorkflowService" -/// @nexus.namespace dotnet="Temporalio.Workflows" -/// @nexus.operations-class java="WorkflowOperations" dotnet="Workflow" +/// @nexus.operations-class java="WorkflowOperations" /// @nexus.delay-load-temporalio-workflow /// @nexus.experimental interface workflow-service { @@ -37,9 +36,10 @@ interface workflow-service { /// python="Workflow type name or callable identifying the workflow to start." /// typescript="Workflow type name or workflow function identifying the workflow to start." /// dotnet="Workflow type name or workflow expression identifying the workflow to start." + /// go="Workflow function identifying the workflow to start." /// @nexus.proto-field "workflow_type" workflow: workflow-function, - /// @nexus.doc "Unique identifier for the workflow execution." + /// @nexus.doc "Unique identifier for the workflow execution. Must be nonempty." /// @nexus.proto-field "workflow_id" id: string, /// @nexus.doc "Task queue to run the workflow on." @@ -48,16 +48,20 @@ interface workflow-service { /// python="Signal name or callable to send with the start request." /// typescript="Signal name or signal definition to send with the start request." /// dotnet="Signal name or signal expression to send with the start request." + /// go="Signal name to send with the start request." /// @nexus.proto-field "signal_name" signal: signal-function, - /// @nexus.doc "Total workflow execution timeout, including retries and continue-as-new." + /// @nexus.doc "Total workflow execution timeout, including retries and continue-as-new. Defaults to unlimited." /// @nexus.proto-field "workflow_execution_timeout" + /// @nexus.name go="WorkflowExecutionTimeout" execution-timeout: option, - /// @nexus.doc "Timeout of a single workflow run." + /// @nexus.doc "Timeout of a single workflow run. Defaults to the workflow execution timeout." /// @nexus.proto-field "workflow_run_timeout" + /// @nexus.name go="WorkflowRunTimeout" run-timeout: option, - /// @nexus.doc "Timeout of a single workflow task." + /// @nexus.doc "Timeout of a single workflow task. Defaults to 10 seconds." /// @nexus.proto-field "workflow_task_timeout" + /// @nexus.name go="WorkflowTaskTimeout" task-timeout: option, /// @nexus.omit identity: placeholder, @@ -66,9 +70,11 @@ interface workflow-service { /// @nexus.doc "Behavior when a closed workflow with the same ID exists. Default is allow-duplicate." /// @nexus.proto-field "workflow_id_reuse_policy" /// @nexus.default "allow-duplicate" + /// @nexus.name go="WorkflowIDReusePolicy" id-reuse-policy: workflow-id-reuse-policy, - /// @nexus.doc "Behavior when a workflow is currently running with the same ID. Set to use-existing for idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is terminate-if-running." + /// @nexus.doc "Behavior when a workflow is currently running with the same ID. Set to use-existing for idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is terminate-if-running. Defaults to use-existing." /// @nexus.proto-field "workflow_id_conflict_policy" + /// @nexus.name go="WorkflowIDConflictPolicy" id-conflict-policy: option, /// @nexus.doc "Retry policy for the workflow." retry-policy: option, @@ -77,6 +83,7 @@ interface workflow-service { /// @nexus.doc "Memo for the workflow." memo: option, /// @nexus.doc "Typed search attributes for the workflow." + /// @nexus.name go="TypedSearchAttributes" search-attributes: option, /// @nexus.doc "Priority of the workflow execution." priority: option, @@ -85,12 +92,15 @@ interface workflow-service { /// @nexus.doc "Amount of time to wait before starting the workflow. This does not work with cron-schedule." /// @nexus.proto-field "workflow_start_delay" start-delay: option, + /// @nexus.doc "Static metadata for the workflow execution." user-metadata: option, - /// @nexus.source java="workflowNamespace()" python="workflow_namespace" typescript="workflowNamespace" dotnet="TemporalWorkflowContext.WorkflowNamespace" + /// @nexus.source java="workflowNamespace()" python="workflow_namespace()" typescript="workflowNamespace()" go="WorkflowNamespace(ctx)" dotnet="TemporalWorkflowContext.WorkflowNamespace()" + /// @nexus.doc "Namespace of the workflow execution." namespace: string, /// @nexus.omit control: placeholder, /// @nexus.api-omit + /// @nexus.doc "Headers for the request." /// @nexus.proto-field "header" headers: option
, /// @nexus.omit @@ -99,32 +109,38 @@ interface workflow-service { time-skipping-config: placeholder, } + /// @nexus.doc "Result of signaling a workflow and starting it if needed." /// @nexus.experimental /// @nexus.proto "temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse" typescript-import="@temporalio/proto" record signal-with-start-workflow-response { + /// @nexus.doc "Run ID of the started workflow." run-id: option, + /// @nexus.doc "Whether the workflow was started." started: option, /// @nexus.omit + first-execution-run-id: placeholder, + /// @nexus.omit signal-link: placeholder, - first-execution-run-id: string, } /// @nexus.doc /// "Signal a workflow, starting it first if needed." + /// go="Signal a workflow, starting it first if needed." /// returns="A workflow handle to the started workflow." /// @nexus.output-transform /// java-type="io.temporal.workflow.ExternalWorkflowStub" /// java="io.temporal.workflow.Workflow.newUntypedExternalWorkflowStub(io.temporal.api.common.v1.WorkflowExecution.newBuilder().setWorkflowId(request.getId()).setRunId(result.getRunId() == null ? \"\" : result.getRunId()).build())" /// python-type="temporalio.workflow.ExternalWorkflowHandle[WorkflowResult]" /// python="temporalio.workflow.get_external_workflow_handle(request.id, run_id=result.run_id)" - /// typescript-type="workflow.ExternalWorkflowHandle" + /// typescript-type="ExternalWorkflowHandle" + /// typescript-type-import="../../../../workflow" /// typescript="workflow.getExternalWorkflowHandle(request.id, result.runId ?? undefined)" /// typescript-import="@temporalio/workflow" /// dotnet-type="Temporalio.Workflows.ExternalWorkflowHandle" /// dotnet="Temporalio.Workflows.Workflow.GetExternalWorkflowHandle(request.Id, result.RunId)" /// @nexus.operation name="SignalWithStartWorkflowExecution" + /// @nexus.serialization-context java="signalWithStartWorkflowSerializationContext" python="signal_with_start_workflow_serialization_context" typescript="signalWithStartWorkflowSerializationContext" dotnet="WorkflowServiceSerializationContexts.SignalWithStartWorkflow" go="SignalWithStartWorkflowSerializationContext" /// @nexus.experimental - /// @nexus.serialization-context java="signalWithStartWorkflowSerializationContext" signal-with-start-workflow: func( request: signal-with-start-workflow-request, ) -> signal-with-start-workflow-response; From 1f3f4dbece776ee93105b209acfb80da7c46a33e Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Mon, 19 Oct 2026 15:29:33 -0700 Subject: [PATCH 05/17] Format generated system APIs during regeneration --- temporal-sdk/build.gradle | 2 +- .../io/temporal/workflow/NexgenRuntime.java | 281 +++++-- .../SignalWithStartWorkflowRequest.java | 758 ++++++++++++++---- .../SignalWithStartWorkflowResponse.java | 113 ++- .../workflow/SystemNexusOperations.java | 34 +- ...ystemNexusWorkflowOutboundInterceptor.java | 35 +- .../io/temporal/workflow/UserMetadata.java | 128 ++- .../temporal/workflow/WorkflowOperations.java | 37 +- .../io/temporal/workflow/WorkflowService.java | 3 +- temporal-sdk/src/main/nexus/README.md | 5 + 10 files changed, 1104 insertions(+), 292 deletions(-) diff --git a/temporal-sdk/build.gradle b/temporal-sdk/build.gradle index 317deaad8d..11011fd70f 100644 --- a/temporal-sdk/build.gradle +++ b/temporal-sdk/build.gradle @@ -350,7 +350,7 @@ tasks.register('generateNexusSystemApi', Exec) { outputs.dir(nexusGeneratedDir) outputs.upToDateWhen { false } commandLine binary.get(), 'java', file('src/main/nexus/workflow-service.wit'), - file('src/main/nexus/deps'), '--native-api', '--system-nexus', + file('src/main/nexus/deps'), '--native-api', '--system-nexus', '--format', '--support-package', 'io.temporal.internal.nexus.system.TemporalModelConverters', '--package-name', 'io.temporal.workflow', '--descriptors', project(':temporal-serviceclient').layout.buildDirectory.file('generated/descriptors/temporal-api.desc').get().asFile, diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java index 85659e4c73..540b91d8db 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java @@ -1,47 +1,81 @@ // Generated by nexgen. DO NOT EDIT! package io.temporal.workflow; + /** Shared conversion helpers for generated WIT models. */ @SuppressWarnings({"unchecked", "rawtypes"}) public final class NexgenRuntime { private NexgenRuntime() {} - private static final ThreadLocal CONVERTER = new ThreadLocal<>(); + + private static final ThreadLocal CONVERTER = + new ThreadLocal<>(); + public static io.temporal.common.converter.DataConverter dataConverter() { io.temporal.common.converter.DataConverter value = CONVERTER.get(); - return value == null ? io.temporal.common.converter.DefaultDataConverter.STANDARD_INSTANCE : value; + return value == null + ? io.temporal.common.converter.DefaultDataConverter.STANDARD_INSTANCE + : value; } - public static T withDataConverter(io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { + + public static T withDataConverter( + io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { io.temporal.common.converter.DataConverter previous = CONVERTER.get(); CONVERTER.set(converter); - try { return action.get(); } - finally { if (previous == null) CONVERTER.remove(); else CONVERTER.set(previous); } + try { + return action.get(); + } finally { + if (previous == null) CONVERTER.remove(); + else CONVERTER.set(previous); + } } - public static java.lang.reflect.Type parameterized(final Class raw, final java.lang.reflect.Type... arguments) { + + public static java.lang.reflect.Type parameterized( + final Class raw, final java.lang.reflect.Type... arguments) { return new java.lang.reflect.ParameterizedType() { - public java.lang.reflect.Type getRawType() { return raw; } - public java.lang.reflect.Type getOwnerType() { return raw.getDeclaringClass(); } - public java.lang.reflect.Type[] getActualTypeArguments() { return arguments.clone(); } + public java.lang.reflect.Type getRawType() { + return raw; + } + + public java.lang.reflect.Type getOwnerType() { + return raw.getDeclaringClass(); + } + + public java.lang.reflect.Type[] getActualTypeArguments() { + return arguments.clone(); + } }; } + public static java.lang.reflect.Type argument(java.lang.reflect.Type type, int index) { - return type instanceof java.lang.reflect.ParameterizedType ? ((java.lang.reflect.ParameterizedType) type).getActualTypeArguments()[index] : Object.class; + return type instanceof java.lang.reflect.ParameterizedType + ? ((java.lang.reflect.ParameterizedType) type).getActualTypeArguments()[index] + : Object.class; } - public static Object get(com.google.protobuf.Message message, String name) { return message.getField(field(message, name)); } + + public static Object get(com.google.protobuf.Message message, String name) { + return message.getField(field(message, name)); + } + public static boolean has(com.google.protobuf.Message message, String name) { com.google.protobuf.Descriptors.FieldDescriptor field = field(message, name); return field.isRepeated() ? message.getRepeatedFieldCount(field) > 0 : message.hasField(field); } - private static com.google.protobuf.Descriptors.FieldDescriptor field(com.google.protobuf.MessageOrBuilder message, String name) { - com.google.protobuf.Descriptors.FieldDescriptor field = message.getDescriptorForType().findFieldByName(name); + + private static com.google.protobuf.Descriptors.FieldDescriptor field( + com.google.protobuf.MessageOrBuilder message, String name) { + com.google.protobuf.Descriptors.FieldDescriptor field = + message.getDescriptorForType().findFieldByName(name); if (field == null) throw new IllegalArgumentException("Unknown protobuf field: " + name); return field; } + public static void set(com.google.protobuf.Message.Builder builder, String name, Object value) { com.google.protobuf.Descriptors.FieldDescriptor field = field(builder, name); if (field.isMapField() && value instanceof java.util.Map) { for (Object raw : ((java.util.Map) value).entrySet()) { java.util.Map.Entry entry = (java.util.Map.Entry) raw; com.google.protobuf.Message.Builder entryBuilder = builder.newBuilderForField(field); - set(entryBuilder, "key", entry.getKey()); set(entryBuilder, "value", entry.getValue()); + set(entryBuilder, "key", entry.getKey()); + set(entryBuilder, "value", entry.getValue()); builder.addRepeatedField(field, entryBuilder.build()); } } else if (field.isRepeated()) { @@ -52,96 +86,219 @@ public static void set(com.google.protobuf.Message.Builder builder, String name, builder.setField(field, wireValue(field, value)); } } - private static Object wireValue(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + + private static Object wireValue( + com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { if (field.getJavaType() == com.google.protobuf.Descriptors.FieldDescriptor.JavaType.ENUM) { if (value instanceof String) { String name = (String) value; - com.google.protobuf.Descriptors.EnumValueDescriptor member = field.getEnumType().findValueByName(name); + com.google.protobuf.Descriptors.EnumValueDescriptor member = + field.getEnumType().findValueByName(name); if (member != null) return member; - for (com.google.protobuf.Descriptors.EnumValueDescriptor candidate : field.getEnumType().getValues()) if (candidate.getName().endsWith("_" + name)) return candidate; + for (com.google.protobuf.Descriptors.EnumValueDescriptor candidate : + field.getEnumType().getValues()) + if (candidate.getName().endsWith("_" + name)) return candidate; throw new IllegalArgumentException("Unknown enum value: " + name); } - if (value instanceof Number) return field.getEnumType().findValueByNumberCreatingIfUnknown(((Number) value).intValue()); - if (value instanceof com.google.protobuf.ProtocolMessageEnum) return ((com.google.protobuf.ProtocolMessageEnum) value).getValueDescriptor(); + if (value instanceof Number) + return field.getEnumType().findValueByNumberCreatingIfUnknown(((Number) value).intValue()); + if (value instanceof com.google.protobuf.ProtocolMessageEnum) + return ((com.google.protobuf.ProtocolMessageEnum) value).getValueDescriptor(); } if (value instanceof Number) { switch (field.getJavaType()) { - case INT: return ((Number) value).intValue(); - case LONG: return ((Number) value).longValue(); - case FLOAT: return ((Number) value).floatValue(); - case DOUBLE: return ((Number) value).doubleValue(); - default: break; + case INT: + return ((Number) value).intValue(); + case LONG: + return ((Number) value).longValue(); + case FLOAT: + return ((Number) value).floatValue(); + case DOUBLE: + return ((Number) value).doubleValue(); + default: + break; } } return value; } + public static java.util.Map protoMap(Object value) { java.util.Map result = new java.util.LinkedHashMap<>(); - for (com.google.protobuf.Message entry : (java.util.List) value) result.put(get(entry, "key"), get(entry, "value")); + for (com.google.protobuf.Message entry : (java.util.List) value) + result.put(get(entry, "key"), get(entry, "value")); return result; } - public static java.util.List map(java.util.List values, java.util.function.Function function) { + + public static java.util.List map( + java.util.List values, java.util.function.Function function) { java.util.List result = new java.util.ArrayList<>(values.size()); - for (A value : values) result.add(function.apply(value)); return result; + for (A value : values) result.add(function.apply(value)); + return result; } - public static java.util.Map mapValues(java.util.Map values, java.util.function.Function key, java.util.function.Function value) { + + public static java.util.Map mapValues( + java.util.Map values, + java.util.function.Function key, + java.util.function.Function value) { java.util.Map result = new java.util.LinkedHashMap<>(); - for (java.util.Map.Entry entry : values.entrySet()) result.put(key.apply(entry.getKey()), value.apply(entry.getValue())); return result; + for (java.util.Map.Entry entry : values.entrySet()) + result.put(key.apply(entry.getKey()), value.apply(entry.getValue())); + return result; } + public static final class FunctionReference { - private final F callable; private final N name; - private FunctionReference(F callable, N name) { this.callable = callable; this.name = name; } - public static FunctionReference callable(F value) { return new FunctionReference<>(java.util.Objects.requireNonNull(value), null); } - public static FunctionReference named(N value) { return new FunctionReference<>(null, java.util.Objects.requireNonNull(value)); } - public boolean isNamed() { return name != null; } - public F getCallable() { return callable; } - public N getName() { return name; } - } - public interface Flag { long getBit(); } - public static long flags(java.util.Set> values) { long result = 0; for (Enum value : values) result |= ((Flag) value).getBit(); return result; } - public static & Flag> java.util.EnumSet flagsFromNumber(long bits, Class type) { + private final F callable; + private final N name; + + private FunctionReference(F callable, N name) { + this.callable = callable; + this.name = name; + } + + public static FunctionReference callable(F value) { + return new FunctionReference<>(java.util.Objects.requireNonNull(value), null); + } + + public static FunctionReference named(N value) { + return new FunctionReference<>(null, java.util.Objects.requireNonNull(value)); + } + + public boolean isNamed() { + return name != null; + } + + public F getCallable() { + return callable; + } + + public N getName() { + return name; + } + } + + public interface Flag { + long getBit(); + } + + public static long flags(java.util.Set> values) { + long result = 0; + for (Enum value : values) result |= ((Flag) value).getBit(); + return result; + } + + public static & Flag> java.util.EnumSet flagsFromNumber( + long bits, Class type) { java.util.EnumSet result = java.util.EnumSet.noneOf(type); for (E value : type.getEnumConstants()) if ((bits & value.getBit()) != 0) result.add(value); return result; } - public static Object decode(Object value, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type type) { - Class raw = type instanceof Class ? (Class) type : type instanceof java.lang.reflect.ParameterizedType ? (Class) ((java.lang.reflect.ParameterizedType) type).getRawType() : Object.class; - if (value instanceof io.temporal.api.common.v1.Payload) return converter.fromPayload((io.temporal.api.common.v1.Payload) value, raw, type); + + public static Object decode( + Object value, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type type) { + Class raw = + type instanceof Class + ? (Class) type + : type instanceof java.lang.reflect.ParameterizedType + ? (Class) ((java.lang.reflect.ParameterizedType) type).getRawType() + : Object.class; + if (value instanceof io.temporal.api.common.v1.Payload) + return converter.fromPayload((io.temporal.api.common.v1.Payload) value, raw, type); io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; return converter.fromPayloads(0, java.util.Optional.of(payloads), raw, type); } - public static java.util.List decodeSequence(Object value, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type element) { + + public static java.util.List decodeSequence( + Object value, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type element) { io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; - Class raw = element instanceof Class ? (Class) element : element instanceof java.lang.reflect.ParameterizedType ? (Class) ((java.lang.reflect.ParameterizedType) element).getRawType() : Object.class; + Class raw = + element instanceof Class + ? (Class) element + : element instanceof java.lang.reflect.ParameterizedType + ? (Class) ((java.lang.reflect.ParameterizedType) element).getRawType() + : Object.class; java.util.List result = new java.util.ArrayList<>(); - for (io.temporal.api.common.v1.Payload payload : payloads.getPayloadsList()) result.add(converter.fromPayload(payload, raw, element)); + for (io.temporal.api.common.v1.Payload payload : payloads.getPayloadsList()) + result.add(converter.fromPayload(payload, raw, element)); return result; } + @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Result.Deserializer.class) public static final class Result { - private final boolean ok; private final Object value; - private Result(boolean ok, Object value) { this.ok = ok; this.value = value; } - public static Result ok(O value) { return new Result<>(true, value); } - public static Result err(E value) { return new Result<>(false, value); } + private final boolean ok; + private final Object value; + + private Result(boolean ok, Object value) { + this.ok = ok; + this.value = value; + } + + public static Result ok(O value) { + return new Result<>(true, value); + } + + public static Result err(E value) { + return new Result<>(false, value); + } + @com.fasterxml.jackson.annotation.JsonIgnore - public boolean isOk() { return ok; } - public String getTag() { return ok ? "ok" : "err"; } - public Object getValue() { return value; } + public boolean isOk() { + return ok; + } + + public String getTag() { + return ok ? "ok" : "err"; + } + + public Object getValue() { + return value; + } + @com.fasterxml.jackson.annotation.JsonIgnore - public O getOk() { if (!ok) throw new IllegalStateException("Error result"); return (O) value; } + public O getOk() { + if (!ok) throw new IllegalStateException("Error result"); + return (O) value; + } + @com.fasterxml.jackson.annotation.JsonIgnore - public E getErr() { if (ok) throw new IllegalStateException("Success result"); return (E) value; } - public static final class Deserializer extends com.fasterxml.jackson.databind.JsonDeserializer implements com.fasterxml.jackson.databind.deser.ContextualDeserializer { + public E getErr() { + if (ok) throw new IllegalStateException("Success result"); + return (E) value; + } + + public static final class Deserializer + extends com.fasterxml.jackson.databind.JsonDeserializer + implements com.fasterxml.jackson.databind.deser.ContextualDeserializer { private final com.fasterxml.jackson.databind.JavaType type; - public Deserializer() { this(null); } - private Deserializer(com.fasterxml.jackson.databind.JavaType type) { this.type = type; } - public com.fasterxml.jackson.databind.JsonDeserializer createContextual(com.fasterxml.jackson.databind.DeserializationContext context, com.fasterxml.jackson.databind.BeanProperty property) { return new Deserializer(context.getContextualType()); } - public Result deserialize(com.fasterxml.jackson.core.JsonParser parser, com.fasterxml.jackson.databind.DeserializationContext context) throws java.io.IOException { + + public Deserializer() { + this(null); + } + + private Deserializer(com.fasterxml.jackson.databind.JavaType type) { + this.type = type; + } + + public com.fasterxml.jackson.databind.JsonDeserializer createContextual( + com.fasterxml.jackson.databind.DeserializationContext context, + com.fasterxml.jackson.databind.BeanProperty property) { + return new Deserializer(context.getContextualType()); + } + + public Result deserialize( + com.fasterxml.jackson.core.JsonParser parser, + com.fasterxml.jackson.databind.DeserializationContext context) + throws java.io.IOException { com.fasterxml.jackson.databind.JsonNode node = parser.getCodec().readTree(parser); String tag = node.get("tag").asText(); - if (!"ok".equals(tag) && !"err".equals(tag)) throw new java.io.IOException("Unknown result tag: " + tag); + if (!"ok".equals(tag) && !"err".equals(tag)) + throw new java.io.IOException("Unknown result tag: " + tag); boolean ok = "ok".equals(tag); - Object value = context.readTreeAsValue(node.get("value"), type.containedTypeOrUnknown(ok ? 0 : 1)); + Object value = + context.readTreeAsValue(node.get("value"), type.containedTypeOrUnknown(ok ? 0 : 1)); return new Result(ok, value); } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java index 15ee3483c1..da32092827 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java @@ -1,98 +1,111 @@ // Generated by nexgen v0.2.9. DO NOT EDIT! package io.temporal.workflow; -/** - * Request fields for signaling a workflow, starting it first if needed. - */ -@io.temporal.common.converter.TransferTypeConvertible(SignalWithStartWorkflowRequest.Converter.class) +/** Request fields for signaling a workflow, starting it first if needed. */ +@io.temporal.common.converter.TransferTypeConvertible( + SignalWithStartWorkflowRequest.Converter.class) @SuppressWarnings({"unchecked", "rawtypes"}) public final class SignalWithStartWorkflowRequest { private final String workflow; - /** - * Arguments for the workflow. - */ + + /** Arguments for the workflow. */ private final java.util.List args; - /** - * Unique identifier for the workflow execution. Must be nonempty. - */ + + /** Unique identifier for the workflow execution. Must be nonempty. */ private final String id; - /** - * Task queue to run the workflow on. - */ + + /** Task queue to run the workflow on. */ private final String taskQueue; + private final String signal; - /** - * Arguments for the signal. - */ + + /** Arguments for the signal. */ private final java.util.List signalArgs; + /** - * Total workflow execution timeout, including retries and continue-as-new. Defaults - * to unlimited. + * Total workflow execution timeout, including retries and continue-as-new. Defaults to unlimited. */ private final java.time.Duration executionTimeout; - /** - * Timeout of a single workflow run. Defaults to the workflow execution timeout. - */ + + /** Timeout of a single workflow run. Defaults to the workflow execution timeout. */ private final java.time.Duration runTimeout; - /** - * Timeout of a single workflow task. Defaults to 10 seconds. - */ + + /** Timeout of a single workflow task. Defaults to 10 seconds. */ private final java.time.Duration taskTimeout; - /** - * Behavior when a closed workflow with the same ID exists. Default is - * allow-duplicate. - */ + + /** Behavior when a closed workflow with the same ID exists. Default is allow-duplicate. */ private final io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy; + /** - * Behavior when a workflow is currently running with the same ID. Set to use-existing - * for idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is + * Behavior when a workflow is currently running with the same ID. Set to use-existing for + * idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is * terminate-if-running. Defaults to use-existing. */ private final io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy; - /** - * Retry policy for the workflow. - */ + + /** Retry policy for the workflow. */ private final io.temporal.common.RetryOptions retryPolicy; - /** - * Cron schedule for recurring workflow executions. See - * https://docs.temporal.io/cron-job. - */ + + /** Cron schedule for recurring workflow executions. See https://docs.temporal.io/cron-job. */ private final String cronSchedule; - /** - * Memo for the workflow. - */ + + /** Memo for the workflow. */ private final java.util.Map memo; - /** - * Typed search attributes for the workflow. - */ + + /** Typed search attributes for the workflow. */ private final io.temporal.common.SearchAttributes searchAttributes; - /** - * Priority of the workflow execution. - */ + + /** Priority of the workflow execution. */ private final io.temporal.common.Priority priority; - /** - * Override for workflow versioning behavior. - */ + + /** Override for workflow versioning behavior. */ private final io.temporal.common.VersioningOverride versioningOverride; - /** - * Amount of time to wait before starting the workflow. This does not work with - * cron-schedule. - */ + + /** Amount of time to wait before starting the workflow. This does not work with cron-schedule. */ private final java.time.Duration startDelay; - /** - * Static metadata for the workflow execution. - */ + + /** Static metadata for the workflow execution. */ private final io.temporal.workflow.UserMetadata userMetadata; - /** - * Namespace of the workflow execution. - */ + + /** Namespace of the workflow execution. */ private final String namespace; - /** - * Headers for the request. - */ + + /** Headers for the request. */ private final java.util.Map headers; + @com.fasterxml.jackson.annotation.JsonCreator - public SignalWithStartWorkflowRequest(@com.fasterxml.jackson.annotation.JsonProperty("workflow") String workflow, @com.fasterxml.jackson.annotation.JsonProperty("args") java.util.List args, @com.fasterxml.jackson.annotation.JsonProperty("id") String id, @com.fasterxml.jackson.annotation.JsonProperty("taskQueue") String taskQueue, @com.fasterxml.jackson.annotation.JsonProperty("signal") String signal, @com.fasterxml.jackson.annotation.JsonProperty("signalArgs") java.util.List signalArgs, @com.fasterxml.jackson.annotation.JsonProperty("executionTimeout") java.time.Duration executionTimeout, @com.fasterxml.jackson.annotation.JsonProperty("runTimeout") java.time.Duration runTimeout, @com.fasterxml.jackson.annotation.JsonProperty("taskTimeout") java.time.Duration taskTimeout, @com.fasterxml.jackson.annotation.JsonProperty("idReusePolicy") io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy, @com.fasterxml.jackson.annotation.JsonProperty("idConflictPolicy") io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy, @com.fasterxml.jackson.annotation.JsonProperty("retryPolicy") io.temporal.common.RetryOptions retryPolicy, @com.fasterxml.jackson.annotation.JsonProperty("cronSchedule") String cronSchedule, @com.fasterxml.jackson.annotation.JsonProperty("memo") java.util.Map memo, @com.fasterxml.jackson.annotation.JsonProperty("searchAttributes") io.temporal.common.SearchAttributes searchAttributes, @com.fasterxml.jackson.annotation.JsonProperty("priority") io.temporal.common.Priority priority, @com.fasterxml.jackson.annotation.JsonProperty("versioningOverride") io.temporal.common.VersioningOverride versioningOverride, @com.fasterxml.jackson.annotation.JsonProperty("startDelay") java.time.Duration startDelay, @com.fasterxml.jackson.annotation.JsonProperty("userMetadata") io.temporal.workflow.UserMetadata userMetadata, @com.fasterxml.jackson.annotation.JsonProperty("namespace") String namespace, @com.fasterxml.jackson.annotation.JsonProperty("headers") java.util.Map headers) { + public SignalWithStartWorkflowRequest( + @com.fasterxml.jackson.annotation.JsonProperty("workflow") String workflow, + @com.fasterxml.jackson.annotation.JsonProperty("args") java.util.List args, + @com.fasterxml.jackson.annotation.JsonProperty("id") String id, + @com.fasterxml.jackson.annotation.JsonProperty("taskQueue") String taskQueue, + @com.fasterxml.jackson.annotation.JsonProperty("signal") String signal, + @com.fasterxml.jackson.annotation.JsonProperty("signalArgs") + java.util.List signalArgs, + @com.fasterxml.jackson.annotation.JsonProperty("executionTimeout") + java.time.Duration executionTimeout, + @com.fasterxml.jackson.annotation.JsonProperty("runTimeout") java.time.Duration runTimeout, + @com.fasterxml.jackson.annotation.JsonProperty("taskTimeout") java.time.Duration taskTimeout, + @com.fasterxml.jackson.annotation.JsonProperty("idReusePolicy") + io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy, + @com.fasterxml.jackson.annotation.JsonProperty("idConflictPolicy") + io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy, + @com.fasterxml.jackson.annotation.JsonProperty("retryPolicy") + io.temporal.common.RetryOptions retryPolicy, + @com.fasterxml.jackson.annotation.JsonProperty("cronSchedule") String cronSchedule, + @com.fasterxml.jackson.annotation.JsonProperty("memo") java.util.Map memo, + @com.fasterxml.jackson.annotation.JsonProperty("searchAttributes") + io.temporal.common.SearchAttributes searchAttributes, + @com.fasterxml.jackson.annotation.JsonProperty("priority") + io.temporal.common.Priority priority, + @com.fasterxml.jackson.annotation.JsonProperty("versioningOverride") + io.temporal.common.VersioningOverride versioningOverride, + @com.fasterxml.jackson.annotation.JsonProperty("startDelay") java.time.Duration startDelay, + @com.fasterxml.jackson.annotation.JsonProperty("userMetadata") + io.temporal.workflow.UserMetadata userMetadata, + @com.fasterxml.jackson.annotation.JsonProperty("namespace") String namespace, + @com.fasterxml.jackson.annotation.JsonProperty("headers") + java.util.Map headers) { this.workflow = workflow; this.args = args; this.id = id; @@ -115,32 +128,106 @@ public SignalWithStartWorkflowRequest(@com.fasterxml.jackson.annotation.JsonProp this.namespace = namespace; this.headers = headers; } - public String getWorkflow() { return workflow; } - public java.util.List getArgs() { return args; } - public String getId() { return id; } - public String getTaskQueue() { return taskQueue; } - public String getSignal() { return signal; } - public java.util.List getSignalArgs() { return signalArgs; } - public java.time.Duration getExecutionTimeout() { return executionTimeout; } - public java.time.Duration getRunTimeout() { return runTimeout; } - public java.time.Duration getTaskTimeout() { return taskTimeout; } - public io.temporal.api.enums.v1.WorkflowIdReusePolicy getIdReusePolicy() { return idReusePolicy; } - public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getIdConflictPolicy() { return idConflictPolicy; } - public io.temporal.common.RetryOptions getRetryPolicy() { return retryPolicy; } - public String getCronSchedule() { return cronSchedule; } - public java.util.Map getMemo() { return memo; } - public io.temporal.common.SearchAttributes getSearchAttributes() { return searchAttributes; } - public io.temporal.common.Priority getPriority() { return priority; } - public io.temporal.common.VersioningOverride getVersioningOverride() { return versioningOverride; } - public java.time.Duration getStartDelay() { return startDelay; } - public io.temporal.workflow.UserMetadata getUserMetadata() { return userMetadata; } - public String getNamespace() { return namespace; } - public java.util.Map getHeaders() { return headers; } - public Builder toBuilder() { return newBuilder(this); } - public static Builder newBuilder(SignalWithStartWorkflowRequest value) { return new Builder(value); } - public static Builder newBuilder() { return new Builder(); } + + public String getWorkflow() { + return workflow; + } + + public java.util.List getArgs() { + return args; + } + + public String getId() { + return id; + } + + public String getTaskQueue() { + return taskQueue; + } + + public String getSignal() { + return signal; + } + + public java.util.List getSignalArgs() { + return signalArgs; + } + + public java.time.Duration getExecutionTimeout() { + return executionTimeout; + } + + public java.time.Duration getRunTimeout() { + return runTimeout; + } + + public java.time.Duration getTaskTimeout() { + return taskTimeout; + } + + public io.temporal.api.enums.v1.WorkflowIdReusePolicy getIdReusePolicy() { + return idReusePolicy; + } + + public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getIdConflictPolicy() { + return idConflictPolicy; + } + + public io.temporal.common.RetryOptions getRetryPolicy() { + return retryPolicy; + } + + public String getCronSchedule() { + return cronSchedule; + } + + public java.util.Map getMemo() { + return memo; + } + + public io.temporal.common.SearchAttributes getSearchAttributes() { + return searchAttributes; + } + + public io.temporal.common.Priority getPriority() { + return priority; + } + + public io.temporal.common.VersioningOverride getVersioningOverride() { + return versioningOverride; + } + + public java.time.Duration getStartDelay() { + return startDelay; + } + + public io.temporal.workflow.UserMetadata getUserMetadata() { + return userMetadata; + } + + public String getNamespace() { + return namespace; + } + + public java.util.Map getHeaders() { + return headers; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(SignalWithStartWorkflowRequest value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + public static final class Builder { private Builder() {} + private Builder(SignalWithStartWorkflowRequest value) { if (value == null) return; this.workflow = value.workflow; @@ -165,105 +252,458 @@ private Builder(SignalWithStartWorkflowRequest value) { this.namespace = value.namespace; this.headers = value.headers; } + private String workflow = null; - public Builder setWorkflow(String value) { this.workflow = value; return this; } + + public Builder setWorkflow(String value) { + this.workflow = value; + return this; + } + private java.util.List args = null; - public Builder setArgs(java.util.List value) { this.args = value; return this; } + + public Builder setArgs(java.util.List value) { + this.args = value; + return this; + } + private String id = ""; - public Builder setId(String value) { this.id = value; return this; } + + public Builder setId(String value) { + this.id = value; + return this; + } + private String taskQueue = null; - public Builder setTaskQueue(String value) { this.taskQueue = value; return this; } + + public Builder setTaskQueue(String value) { + this.taskQueue = value; + return this; + } + private String signal = ""; - public Builder setSignal(String value) { this.signal = value; return this; } + + public Builder setSignal(String value) { + this.signal = value; + return this; + } + private java.util.List signalArgs = null; - public Builder setSignalArgs(java.util.List value) { this.signalArgs = value; return this; } + + public Builder setSignalArgs(java.util.List value) { + this.signalArgs = value; + return this; + } + private java.time.Duration executionTimeout = null; - public Builder setExecutionTimeout(java.time.Duration value) { this.executionTimeout = value; return this; } + + public Builder setExecutionTimeout(java.time.Duration value) { + this.executionTimeout = value; + return this; + } + private java.time.Duration runTimeout = null; - public Builder setRunTimeout(java.time.Duration value) { this.runTimeout = value; return this; } + + public Builder setRunTimeout(java.time.Duration value) { + this.runTimeout = value; + return this; + } + private java.time.Duration taskTimeout = null; - public Builder setTaskTimeout(java.time.Duration value) { this.taskTimeout = value; return this; } - private io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy = io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(1); - public Builder setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { this.idReusePolicy = value; return this; } + + public Builder setTaskTimeout(java.time.Duration value) { + this.taskTimeout = value; + return this; + } + + private io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy = + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(1); + + public Builder setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { + this.idReusePolicy = value; + return this; + } + private io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy = null; - public Builder setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { this.idConflictPolicy = value; return this; } + + public Builder setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { + this.idConflictPolicy = value; + return this; + } + private io.temporal.common.RetryOptions retryPolicy = null; - public Builder setRetryPolicy(io.temporal.common.RetryOptions value) { this.retryPolicy = value; return this; } + + public Builder setRetryPolicy(io.temporal.common.RetryOptions value) { + this.retryPolicy = value; + return this; + } + private String cronSchedule = null; - public Builder setCronSchedule(String value) { this.cronSchedule = value; return this; } + + public Builder setCronSchedule(String value) { + this.cronSchedule = value; + return this; + } + private java.util.Map memo = null; - public Builder setMemo(java.util.Map value) { this.memo = value; return this; } + + public Builder setMemo(java.util.Map value) { + this.memo = value; + return this; + } + private io.temporal.common.SearchAttributes searchAttributes = null; - public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { this.searchAttributes = value; return this; } + + public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { + this.searchAttributes = value; + return this; + } + private io.temporal.common.Priority priority = null; - public Builder setPriority(io.temporal.common.Priority value) { this.priority = value; return this; } + + public Builder setPriority(io.temporal.common.Priority value) { + this.priority = value; + return this; + } + private io.temporal.common.VersioningOverride versioningOverride = null; - public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { this.versioningOverride = value; return this; } + + public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { + this.versioningOverride = value; + return this; + } + private java.time.Duration startDelay = null; - public Builder setStartDelay(java.time.Duration value) { this.startDelay = value; return this; } + + public Builder setStartDelay(java.time.Duration value) { + this.startDelay = value; + return this; + } + private io.temporal.workflow.UserMetadata userMetadata = null; - public Builder setUserMetadata(io.temporal.workflow.UserMetadata value) { this.userMetadata = value; return this; } + + public Builder setUserMetadata(io.temporal.workflow.UserMetadata value) { + this.userMetadata = value; + return this; + } + private String namespace = null; - public Builder setNamespace(String value) { this.namespace = value; return this; } + + public Builder setNamespace(String value) { + this.namespace = value; + return this; + } + private java.util.Map headers = null; - public Builder setHeaders(java.util.Map value) { this.headers = value; return this; } - public Builder setStaticSummary(Object value) { this.userMetadata = io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata).setStaticSummary(value).build(); return this; } - public Builder setStaticDetails(Object value) { this.userMetadata = io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata).setStaticDetails(value).build(); return this; } - public SignalWithStartWorkflowRequest build() { return new SignalWithStartWorkflowRequest(workflow, args, id, taskQueue, signal, signalArgs, executionTimeout, runTimeout, taskTimeout, idReusePolicy, idConflictPolicy, retryPolicy, cronSchedule, memo, searchAttributes, priority, versioningOverride, startDelay, userMetadata, namespace == null ? io.temporal.internal.nexus.system.TemporalModelConverters.workflowNamespace() : namespace, headers); } + + public Builder setHeaders(java.util.Map value) { + this.headers = value; + return this; + } + + public Builder setStaticSummary(Object value) { + this.userMetadata = + io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata) + .setStaticSummary(value) + .build(); + return this; + } + + public Builder setStaticDetails(Object value) { + this.userMetadata = + io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata) + .setStaticDetails(value) + .build(); + return this; + } + + public SignalWithStartWorkflowRequest build() { + return new SignalWithStartWorkflowRequest( + workflow, + args, + id, + taskQueue, + signal, + signalArgs, + executionTimeout, + runTimeout, + taskTimeout, + idReusePolicy, + idConflictPolicy, + retryPolicy, + cronSchedule, + memo, + searchAttributes, + priority, + versioningOverride, + startDelay, + userMetadata, + namespace == null + ? io.temporal.internal.nexus.system.TemporalModelConverters.workflowNamespace() + : namespace, + headers); + } } - public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto(io.temporal.common.converter.DataConverter converter) { - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder(); - if (this.workflow != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_type", io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeToProto(converter, (this.workflow))); - if (this.args != null) io.temporal.workflow.NexgenRuntime.set(proto, "input", converter.toPayloads((this.args).toArray()).orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto( + io.temporal.common.converter.DataConverter converter) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.Builder proto = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder(); + if (this.workflow != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "workflow_type", + io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeToProto( + converter, (this.workflow))); + if (this.args != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "input", + converter + .toPayloads((this.args).toArray()) + .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); if (this.id != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_id", (this.id)); - if (this.taskQueue != null) io.temporal.workflow.NexgenRuntime.set(proto, "task_queue", io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueToProto(converter, (this.taskQueue))); - if (this.signal != null) io.temporal.workflow.NexgenRuntime.set(proto, "signal_name", (this.signal)); - if (this.signalArgs != null) io.temporal.workflow.NexgenRuntime.set(proto, "signal_input", converter.toPayloads((this.signalArgs).toArray()).orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); - if (this.executionTimeout != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_execution_timeout", io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto(converter, (this.executionTimeout))); - if (this.runTimeout != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_run_timeout", io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto(converter, (this.runTimeout))); - if (this.taskTimeout != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_task_timeout", io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto(converter, (this.taskTimeout))); - if (this.idReusePolicy != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_id_reuse_policy", (this.idReusePolicy).getNumber()); - if (this.idConflictPolicy != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_id_conflict_policy", (this.idConflictPolicy).getNumber()); - if (this.retryPolicy != null) io.temporal.workflow.NexgenRuntime.set(proto, "retry_policy", io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyToProto(converter, (this.retryPolicy))); - if (this.cronSchedule != null) io.temporal.workflow.NexgenRuntime.set(proto, "cron_schedule", (this.cronSchedule)); - if (this.memo != null) io.temporal.workflow.NexgenRuntime.set(proto, "memo", io.temporal.internal.nexus.system.TemporalModelConverters.memoToProto(converter, (this.memo))); - if (this.searchAttributes != null) io.temporal.workflow.NexgenRuntime.set(proto, "search_attributes", io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesToProto(converter, (this.searchAttributes))); - if (this.priority != null) io.temporal.workflow.NexgenRuntime.set(proto, "priority", io.temporal.internal.nexus.system.TemporalModelConverters.priorityToProto(converter, (this.priority))); - if (this.versioningOverride != null) io.temporal.workflow.NexgenRuntime.set(proto, "versioning_override", io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideToProto(converter, (this.versioningOverride))); - if (this.startDelay != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_start_delay", io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto(converter, (this.startDelay))); - if (this.userMetadata != null) io.temporal.workflow.NexgenRuntime.set(proto, "user_metadata", (this.userMetadata).toProto(converter)); - if (this.namespace != null) io.temporal.workflow.NexgenRuntime.set(proto, "namespace", (this.namespace)); - if (this.headers != null) io.temporal.workflow.NexgenRuntime.set(proto, "header", io.temporal.internal.nexus.system.TemporalModelConverters.headerToProto(converter, (this.headers))); + if (this.taskQueue != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "task_queue", + io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueToProto( + converter, (this.taskQueue))); + if (this.signal != null) + io.temporal.workflow.NexgenRuntime.set(proto, "signal_name", (this.signal)); + if (this.signalArgs != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "signal_input", + converter + .toPayloads((this.signalArgs).toArray()) + .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + if (this.executionTimeout != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "workflow_execution_timeout", + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.executionTimeout))); + if (this.runTimeout != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "workflow_run_timeout", + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.runTimeout))); + if (this.taskTimeout != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "workflow_task_timeout", + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.taskTimeout))); + if (this.idReusePolicy != null) + io.temporal.workflow.NexgenRuntime.set( + proto, "workflow_id_reuse_policy", (this.idReusePolicy).getNumber()); + if (this.idConflictPolicy != null) + io.temporal.workflow.NexgenRuntime.set( + proto, "workflow_id_conflict_policy", (this.idConflictPolicy).getNumber()); + if (this.retryPolicy != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "retry_policy", + io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyToProto( + converter, (this.retryPolicy))); + if (this.cronSchedule != null) + io.temporal.workflow.NexgenRuntime.set(proto, "cron_schedule", (this.cronSchedule)); + if (this.memo != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "memo", + io.temporal.internal.nexus.system.TemporalModelConverters.memoToProto( + converter, (this.memo))); + if (this.searchAttributes != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "search_attributes", + io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesToProto( + converter, (this.searchAttributes))); + if (this.priority != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "priority", + io.temporal.internal.nexus.system.TemporalModelConverters.priorityToProto( + converter, (this.priority))); + if (this.versioningOverride != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "versioning_override", + io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideToProto( + converter, (this.versioningOverride))); + if (this.startDelay != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "workflow_start_delay", + io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( + converter, (this.startDelay))); + if (this.userMetadata != null) + io.temporal.workflow.NexgenRuntime.set( + proto, "user_metadata", (this.userMetadata).toProto(converter)); + if (this.namespace != null) + io.temporal.workflow.NexgenRuntime.set(proto, "namespace", (this.namespace)); + if (this.headers != null) + io.temporal.workflow.NexgenRuntime.set( + proto, + "header", + io.temporal.internal.nexus.system.TemporalModelConverters.headerToProto( + converter, (this.headers))); return proto.build(); } - public static SignalWithStartWorkflowRequest fromProto(io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { + + public static SignalWithStartWorkflowRequest fromProto( + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { Builder builder = SignalWithStartWorkflowRequest.newBuilder(); - if (true) builder.setWorkflow(io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto(converter, (io.temporal.api.common.v1.WorkflowType) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_type"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "input")) builder.setArgs((java.util.List) (Object) io.temporal.workflow.NexgenRuntime.decodeSequence(io.temporal.workflow.NexgenRuntime.get(proto, "input"), converter, io.temporal.workflow.NexgenRuntime.argument(new com.fasterxml.jackson.core.type.TypeReference>() {}.getType(), 0))); + if (true) + builder.setWorkflow( + io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto( + converter, + (io.temporal.api.common.v1.WorkflowType) + io.temporal.workflow.NexgenRuntime.get(proto, "workflow_type"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "input")) + builder.setArgs( + (java.util.List) + (Object) + io.temporal.workflow.NexgenRuntime.decodeSequence( + io.temporal.workflow.NexgenRuntime.get(proto, "input"), + converter, + io.temporal.workflow.NexgenRuntime.argument( + new com.fasterxml.jackson.core.type.TypeReference< + java.util.List>() {}.getType(), + 0))); if (true) builder.setId((String) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id")); - if (true) builder.setTaskQueue(io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto(converter, (io.temporal.api.taskqueue.v1.TaskQueue) io.temporal.workflow.NexgenRuntime.get(proto, "task_queue"))); - if (true) builder.setSignal((String) io.temporal.workflow.NexgenRuntime.get(proto, "signal_name")); - if (io.temporal.workflow.NexgenRuntime.has(proto, "signal_input")) builder.setSignalArgs((java.util.List) (Object) io.temporal.workflow.NexgenRuntime.decodeSequence(io.temporal.workflow.NexgenRuntime.get(proto, "signal_input"), converter, io.temporal.workflow.NexgenRuntime.argument(new com.fasterxml.jackson.core.type.TypeReference>() {}.getType(), 0))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_execution_timeout")) builder.setExecutionTimeout(io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto(converter, (com.google.protobuf.Duration) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_execution_timeout"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_run_timeout")) builder.setRunTimeout(io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto(converter, (com.google.protobuf.Duration) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_run_timeout"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_task_timeout")) builder.setTaskTimeout(io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto(converter, (com.google.protobuf.Duration) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_task_timeout"))); - if (true) builder.setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(((com.google.protobuf.Descriptors.EnumValueDescriptor) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id_reuse_policy")).getNumber())); - if (true) builder.setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber(((com.google.protobuf.Descriptors.EnumValueDescriptor) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id_conflict_policy")).getNumber())); - if (io.temporal.workflow.NexgenRuntime.has(proto, "retry_policy")) builder.setRetryPolicy(io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyFromProto(converter, (io.temporal.api.common.v1.RetryPolicy) io.temporal.workflow.NexgenRuntime.get(proto, "retry_policy"))); - if (true) builder.setCronSchedule((String) io.temporal.workflow.NexgenRuntime.get(proto, "cron_schedule")); - if (io.temporal.workflow.NexgenRuntime.has(proto, "memo")) builder.setMemo(io.temporal.internal.nexus.system.TemporalModelConverters.memoFromProto(converter, (io.temporal.api.common.v1.Memo) io.temporal.workflow.NexgenRuntime.get(proto, "memo"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "search_attributes")) builder.setSearchAttributes(io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesFromProto(converter, (io.temporal.api.common.v1.SearchAttributes) io.temporal.workflow.NexgenRuntime.get(proto, "search_attributes"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "priority")) builder.setPriority(io.temporal.internal.nexus.system.TemporalModelConverters.priorityFromProto(converter, (io.temporal.api.common.v1.Priority) io.temporal.workflow.NexgenRuntime.get(proto, "priority"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "versioning_override")) builder.setVersioningOverride(io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideFromProto(converter, (io.temporal.api.workflow.v1.VersioningOverride) io.temporal.workflow.NexgenRuntime.get(proto, "versioning_override"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_start_delay")) builder.setStartDelay(io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto(converter, (com.google.protobuf.Duration) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_start_delay"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "user_metadata")) builder.setUserMetadata(io.temporal.workflow.UserMetadata.fromProto((io.temporal.api.sdk.v1.UserMetadata) io.temporal.workflow.NexgenRuntime.get(proto, "user_metadata"), converter, io.temporal.workflow.UserMetadata.class)); - if (true) builder.setNamespace((String) io.temporal.workflow.NexgenRuntime.get(proto, "namespace")); - if (io.temporal.workflow.NexgenRuntime.has(proto, "header")) builder.setHeaders(io.temporal.internal.nexus.system.TemporalModelConverters.headerFromProto(converter, (io.temporal.api.common.v1.Header) io.temporal.workflow.NexgenRuntime.get(proto, "header"))); + if (true) + builder.setTaskQueue( + io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto( + converter, + (io.temporal.api.taskqueue.v1.TaskQueue) + io.temporal.workflow.NexgenRuntime.get(proto, "task_queue"))); + if (true) + builder.setSignal((String) io.temporal.workflow.NexgenRuntime.get(proto, "signal_name")); + if (io.temporal.workflow.NexgenRuntime.has(proto, "signal_input")) + builder.setSignalArgs( + (java.util.List) + (Object) + io.temporal.workflow.NexgenRuntime.decodeSequence( + io.temporal.workflow.NexgenRuntime.get(proto, "signal_input"), + converter, + io.temporal.workflow.NexgenRuntime.argument( + new com.fasterxml.jackson.core.type.TypeReference< + java.util.List>() {}.getType(), + 0))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_execution_timeout")) + builder.setExecutionTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, + (com.google.protobuf.Duration) + io.temporal.workflow.NexgenRuntime.get(proto, "workflow_execution_timeout"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_run_timeout")) + builder.setRunTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, + (com.google.protobuf.Duration) + io.temporal.workflow.NexgenRuntime.get(proto, "workflow_run_timeout"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_task_timeout")) + builder.setTaskTimeout( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, + (com.google.protobuf.Duration) + io.temporal.workflow.NexgenRuntime.get(proto, "workflow_task_timeout"))); + if (true) + builder.setIdReusePolicy( + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( + ((com.google.protobuf.Descriptors.EnumValueDescriptor) + io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id_reuse_policy")) + .getNumber())); + if (true) + builder.setIdConflictPolicy( + io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber( + ((com.google.protobuf.Descriptors.EnumValueDescriptor) + io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id_conflict_policy")) + .getNumber())); + if (io.temporal.workflow.NexgenRuntime.has(proto, "retry_policy")) + builder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyFromProto( + converter, + (io.temporal.api.common.v1.RetryPolicy) + io.temporal.workflow.NexgenRuntime.get(proto, "retry_policy"))); + if (true) + builder.setCronSchedule( + (String) io.temporal.workflow.NexgenRuntime.get(proto, "cron_schedule")); + if (io.temporal.workflow.NexgenRuntime.has(proto, "memo")) + builder.setMemo( + io.temporal.internal.nexus.system.TemporalModelConverters.memoFromProto( + converter, + (io.temporal.api.common.v1.Memo) + io.temporal.workflow.NexgenRuntime.get(proto, "memo"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "search_attributes")) + builder.setSearchAttributes( + io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesFromProto( + converter, + (io.temporal.api.common.v1.SearchAttributes) + io.temporal.workflow.NexgenRuntime.get(proto, "search_attributes"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "priority")) + builder.setPriority( + io.temporal.internal.nexus.system.TemporalModelConverters.priorityFromProto( + converter, + (io.temporal.api.common.v1.Priority) + io.temporal.workflow.NexgenRuntime.get(proto, "priority"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "versioning_override")) + builder.setVersioningOverride( + io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideFromProto( + converter, + (io.temporal.api.workflow.v1.VersioningOverride) + io.temporal.workflow.NexgenRuntime.get(proto, "versioning_override"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_start_delay")) + builder.setStartDelay( + io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( + converter, + (com.google.protobuf.Duration) + io.temporal.workflow.NexgenRuntime.get(proto, "workflow_start_delay"))); + if (io.temporal.workflow.NexgenRuntime.has(proto, "user_metadata")) + builder.setUserMetadata( + io.temporal.workflow.UserMetadata.fromProto( + (io.temporal.api.sdk.v1.UserMetadata) + io.temporal.workflow.NexgenRuntime.get(proto, "user_metadata"), + converter, + io.temporal.workflow.UserMetadata.class)); + if (true) + builder.setNamespace((String) io.temporal.workflow.NexgenRuntime.get(proto, "namespace")); + if (io.temporal.workflow.NexgenRuntime.has(proto, "header")) + builder.setHeaders( + io.temporal.internal.nexus.system.TemporalModelConverters.headerFromProto( + converter, + (io.temporal.api.common.v1.Header) + io.temporal.workflow.NexgenRuntime.get(proto, "header"))); return builder.build(); } - public static final class Converter implements io.temporal.common.converter.TransferTypeConverter { - public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.class; } - public Object toTransferType(SignalWithStartWorkflowRequest value) { return value == null ? null : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); } - public SignalWithStartWorkflowRequest fromTransferType(Object value, java.lang.reflect.Type valueType) { return value == null ? null : fromProto((io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value, io.temporal.workflow.NexgenRuntime.dataConverter(), valueType); } + + public static final class Converter + implements io.temporal.common.converter.TransferTypeConverter< + SignalWithStartWorkflowRequest> { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { + return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.class; + } + + public Object toTransferType(SignalWithStartWorkflowRequest value) { + return value == null + ? null + : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); + } + + public SignalWithStartWorkflowRequest fromTransferType( + Object value, java.lang.reflect.Type valueType) { + return value == null + ? null + : fromProto( + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value, + io.temporal.workflow.NexgenRuntime.dataConverter(), + valueType); + } } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java index 84a3a5250e..e8bbb8827a 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java @@ -1,58 +1,115 @@ // Generated by nexgen v0.2.9. DO NOT EDIT! package io.temporal.workflow; -/** - * Result of signaling a workflow and starting it if needed. - */ -@io.temporal.common.converter.TransferTypeConvertible(SignalWithStartWorkflowResponse.Converter.class) +/** Result of signaling a workflow and starting it if needed. */ +@io.temporal.common.converter.TransferTypeConvertible( + SignalWithStartWorkflowResponse.Converter.class) @SuppressWarnings({"unchecked", "rawtypes"}) public final class SignalWithStartWorkflowResponse { - /** - * Run ID of the started workflow. - */ + /** Run ID of the started workflow. */ private final String runId; - /** - * Whether the workflow was started. - */ + + /** Whether the workflow was started. */ private final Boolean started; + @com.fasterxml.jackson.annotation.JsonCreator - public SignalWithStartWorkflowResponse(@com.fasterxml.jackson.annotation.JsonProperty("runId") String runId, @com.fasterxml.jackson.annotation.JsonProperty("started") Boolean started) { + public SignalWithStartWorkflowResponse( + @com.fasterxml.jackson.annotation.JsonProperty("runId") String runId, + @com.fasterxml.jackson.annotation.JsonProperty("started") Boolean started) { this.runId = runId; this.started = started; } - public String getRunId() { return runId; } - public Boolean getStarted() { return started; } - public Builder toBuilder() { return newBuilder(this); } - public static Builder newBuilder(SignalWithStartWorkflowResponse value) { return new Builder(value); } - public static Builder newBuilder() { return new Builder(); } + + public String getRunId() { + return runId; + } + + public Boolean getStarted() { + return started; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(SignalWithStartWorkflowResponse value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + public static final class Builder { private Builder() {} + private Builder(SignalWithStartWorkflowResponse value) { if (value == null) return; this.runId = value.runId; this.started = value.started; } + private String runId = null; - public Builder setRunId(String value) { this.runId = value; return this; } + + public Builder setRunId(String value) { + this.runId = value; + return this; + } + private Boolean started = null; - public Builder setStarted(Boolean value) { this.started = value; return this; } - public SignalWithStartWorkflowResponse build() { return new SignalWithStartWorkflowResponse(runId, started); } + + public Builder setStarted(Boolean value) { + this.started = value; + return this; + } + + public SignalWithStartWorkflowResponse build() { + return new SignalWithStartWorkflowResponse(runId, started); + } } - public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto(io.temporal.common.converter.DataConverter converter) { - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); + + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto( + io.temporal.common.converter.DataConverter converter) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); if (this.runId != null) io.temporal.workflow.NexgenRuntime.set(proto, "run_id", (this.runId)); - if (this.started != null) io.temporal.workflow.NexgenRuntime.set(proto, "started", (this.started)); + if (this.started != null) + io.temporal.workflow.NexgenRuntime.set(proto, "started", (this.started)); return proto.build(); } - public static SignalWithStartWorkflowResponse fromProto(io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { + + public static SignalWithStartWorkflowResponse fromProto( + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { Builder builder = SignalWithStartWorkflowResponse.newBuilder(); if (true) builder.setRunId((String) io.temporal.workflow.NexgenRuntime.get(proto, "run_id")); - if (true) builder.setStarted((Boolean) io.temporal.workflow.NexgenRuntime.get(proto, "started")); + if (true) + builder.setStarted((Boolean) io.temporal.workflow.NexgenRuntime.get(proto, "started")); return builder.build(); } - public static final class Converter implements io.temporal.common.converter.TransferTypeConverter { - public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.class; } - public Object toTransferType(SignalWithStartWorkflowResponse value) { return value == null ? null : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); } - public SignalWithStartWorkflowResponse fromTransferType(Object value, java.lang.reflect.Type valueType) { return value == null ? null : fromProto((io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value, io.temporal.workflow.NexgenRuntime.dataConverter(), valueType); } + + public static final class Converter + implements io.temporal.common.converter.TransferTypeConverter< + SignalWithStartWorkflowResponse> { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { + return io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.class; + } + + public Object toTransferType(SignalWithStartWorkflowResponse value) { + return value == null + ? null + : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); + } + + public SignalWithStartWorkflowResponse fromTransferType( + Object value, java.lang.reflect.Type valueType) { + return value == null + ? null + : fromProto( + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value, + io.temporal.workflow.NexgenRuntime.dataConverter(), + valueType); + } } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java index 4942c53178..19b7894340 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusOperations.java @@ -5,12 +5,36 @@ @SuppressWarnings({"unchecked", "rawtypes"}) public final class SystemNexusOperations { private SystemNexusOperations() {} - public static io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput execute(SystemNexusWorkflowOutboundInterceptor interceptor, io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input) { - if ("temporal.api.workflowservice.v1.WorkflowService".equals(input.getService()) && "SignalWithStartWorkflowExecution".equals(input.getOperation())) return (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput) interceptor.executeSignalWithStartWorkflow((io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput) input); - throw new IllegalArgumentException("Unsupported system Nexus operation: " + input.getService() + "/" + input.getOperation()); + + public static + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput< + R> + execute( + SystemNexusWorkflowOutboundInterceptor interceptor, + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + R> + input) { + if ("temporal.api.workflowservice.v1.WorkflowService".equals(input.getService()) + && "SignalWithStartWorkflowExecution".equals(input.getOperation())) + return (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationOutput< + R>) + interceptor.executeSignalWithStartWorkflow( + (io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput) + input); + throw new IllegalArgumentException( + "Unsupported system Nexus operation: " + input.getService() + "/" + input.getOperation()); } - public static io.temporal.payload.context.SerializationContext serializationContext(String service, String operation, Object request) { - if ("temporal.api.workflowservice.v1.WorkflowService".equals(service) && "SignalWithStartWorkflowExecution".equals(operation)) return io.temporal.internal.nexus.system.TemporalModelConverters.signalWithStartWorkflowSerializationContext((io.temporal.workflow.SignalWithStartWorkflowRequest) request); + + public static io.temporal.payload.context.SerializationContext serializationContext( + String service, String operation, Object request) { + if ("temporal.api.workflowservice.v1.WorkflowService".equals(service) + && "SignalWithStartWorkflowExecution".equals(operation)) + return io.temporal.internal.nexus.system.TemporalModelConverters + .signalWithStartWorkflowSerializationContext( + (io.temporal.workflow.SignalWithStartWorkflowRequest) request); return null; } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java index 6413ed91c7..f65d47a8b2 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SystemNexusWorkflowOutboundInterceptor.java @@ -3,10 +3,39 @@ /** Generated typed system Nexus hooks. */ public interface SystemNexusWorkflowOutboundInterceptor { - io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput executeNexusOperation(io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input); - default io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput executeSignalWithStartWorkflow(io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input) { return executeNexusOperation(input); } + + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput< + R> + executeNexusOperation( + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + R> + input); + + default io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationOutput< + io.temporal.workflow.SignalWithStartWorkflowResponse> + executeSignalWithStartWorkflow( + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + io.temporal.workflow.SignalWithStartWorkflowResponse> + input) { + return executeNexusOperation(input); + } + abstract class Base implements SystemNexusWorkflowOutboundInterceptor { protected abstract SystemNexusWorkflowOutboundInterceptor nextSystemNexusInterceptor(); - @Override public io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationOutput executeSignalWithStartWorkflow(io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor.ExecuteNexusOperationInput input) { return nextSystemNexusInterceptor().executeSignalWithStartWorkflow(input); } + + @Override + public io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationOutput< + io.temporal.workflow.SignalWithStartWorkflowResponse> + executeSignalWithStartWorkflow( + io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor + .ExecuteNexusOperationInput< + io.temporal.workflow.SignalWithStartWorkflowResponse> + input) { + return nextSystemNexusInterceptor().executeSignalWithStartWorkflow(input); + } } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java index ffdbc12b34..ded8735e64 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java @@ -1,61 +1,133 @@ // Generated by nexgen v0.2.9. DO NOT EDIT! package io.temporal.workflow; -/** - * Static metadata for a workflow execution. - */ +/** Static metadata for a workflow execution. */ @io.temporal.common.converter.TransferTypeConvertible(UserMetadata.Converter.class) @SuppressWarnings({"unchecked", "rawtypes"}) public final class UserMetadata { /** - * Single-line fixed summary for the workflow execution that may appear in UI and CLI. - * This can be in single-line Temporal Markdown format. + * Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be + * in single-line Temporal Markdown format. */ private final Object staticSummary; + /** - * General fixed details for the workflow execution that may appear in UI and CLI. - * This can be in Temporal Markdown format and can span multiple lines. This value is - * fixed on the workflow execution and cannot be updated. + * General fixed details for the workflow execution that may appear in UI and CLI. This can be in + * Temporal Markdown format and can span multiple lines. This value is fixed on the workflow + * execution and cannot be updated. */ private final Object staticDetails; + @com.fasterxml.jackson.annotation.JsonCreator - public UserMetadata(@com.fasterxml.jackson.annotation.JsonProperty("staticSummary") Object staticSummary, @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") Object staticDetails) { + public UserMetadata( + @com.fasterxml.jackson.annotation.JsonProperty("staticSummary") Object staticSummary, + @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") Object staticDetails) { this.staticSummary = staticSummary; this.staticDetails = staticDetails; } - public Object getStaticSummary() { return staticSummary; } - public Object getStaticDetails() { return staticDetails; } - public Builder toBuilder() { return newBuilder(this); } - public static Builder newBuilder(UserMetadata value) { return new Builder(value); } - public static Builder newBuilder() { return new Builder(); } + + public Object getStaticSummary() { + return staticSummary; + } + + public Object getStaticDetails() { + return staticDetails; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(UserMetadata value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + public static final class Builder { private Builder() {} + private Builder(UserMetadata value) { if (value == null) return; this.staticSummary = value.staticSummary; this.staticDetails = value.staticDetails; } + private Object staticSummary = null; - public Builder setStaticSummary(Object value) { this.staticSummary = value; return this; } + + public Builder setStaticSummary(Object value) { + this.staticSummary = value; + return this; + } + private Object staticDetails = null; - public Builder setStaticDetails(Object value) { this.staticDetails = value; return this; } - public UserMetadata build() { return new UserMetadata(staticSummary, staticDetails); } + + public Builder setStaticDetails(Object value) { + this.staticDetails = value; + return this; + } + + public UserMetadata build() { + return new UserMetadata(staticSummary, staticDetails); + } } - public io.temporal.api.sdk.v1.UserMetadata toProto(io.temporal.common.converter.DataConverter converter) { - io.temporal.api.sdk.v1.UserMetadata.Builder proto = io.temporal.api.sdk.v1.UserMetadata.newBuilder(); - if (this.staticSummary != null) io.temporal.workflow.NexgenRuntime.set(proto, "summary", converter.toPayload((this.staticSummary)).get()); - if (this.staticDetails != null) io.temporal.workflow.NexgenRuntime.set(proto, "details", converter.toPayload((this.staticDetails)).get()); + + public io.temporal.api.sdk.v1.UserMetadata toProto( + io.temporal.common.converter.DataConverter converter) { + io.temporal.api.sdk.v1.UserMetadata.Builder proto = + io.temporal.api.sdk.v1.UserMetadata.newBuilder(); + if (this.staticSummary != null) + io.temporal.workflow.NexgenRuntime.set( + proto, "summary", converter.toPayload((this.staticSummary)).get()); + if (this.staticDetails != null) + io.temporal.workflow.NexgenRuntime.set( + proto, "details", converter.toPayload((this.staticDetails)).get()); return proto.build(); } - public static UserMetadata fromProto(io.temporal.api.sdk.v1.UserMetadata proto, io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { + + public static UserMetadata fromProto( + io.temporal.api.sdk.v1.UserMetadata proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { Builder builder = UserMetadata.newBuilder(); - if (io.temporal.workflow.NexgenRuntime.has(proto, "summary")) builder.setStaticSummary((Object) io.temporal.workflow.NexgenRuntime.decode(io.temporal.workflow.NexgenRuntime.get(proto, "summary"), converter, Object.class)); - if (io.temporal.workflow.NexgenRuntime.has(proto, "details")) builder.setStaticDetails((Object) io.temporal.workflow.NexgenRuntime.decode(io.temporal.workflow.NexgenRuntime.get(proto, "details"), converter, Object.class)); + if (io.temporal.workflow.NexgenRuntime.has(proto, "summary")) + builder.setStaticSummary( + (Object) + io.temporal.workflow.NexgenRuntime.decode( + io.temporal.workflow.NexgenRuntime.get(proto, "summary"), + converter, + Object.class)); + if (io.temporal.workflow.NexgenRuntime.has(proto, "details")) + builder.setStaticDetails( + (Object) + io.temporal.workflow.NexgenRuntime.decode( + io.temporal.workflow.NexgenRuntime.get(proto, "details"), + converter, + Object.class)); return builder.build(); } - public static final class Converter implements io.temporal.common.converter.TransferTypeConverter { - public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { return io.temporal.api.sdk.v1.UserMetadata.class; } - public Object toTransferType(UserMetadata value) { return value == null ? null : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); } - public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueType) { return value == null ? null : fromProto((io.temporal.api.sdk.v1.UserMetadata) value, io.temporal.workflow.NexgenRuntime.dataConverter(), valueType); } + + public static final class Converter + implements io.temporal.common.converter.TransferTypeConverter { + public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) { + return io.temporal.api.sdk.v1.UserMetadata.class; + } + + public Object toTransferType(UserMetadata value) { + return value == null + ? null + : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); + } + + public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueType) { + return value == null + ? null + : fromProto( + (io.temporal.api.sdk.v1.UserMetadata) value, + io.temporal.workflow.NexgenRuntime.dataConverter(), + valueType); + } } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java index 843b617e47..529c09852e 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java @@ -4,10 +4,37 @@ @SuppressWarnings({"unchecked", "rawtypes"}) public abstract class WorkflowOperations { protected WorkflowOperations() {} - public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow(io.temporal.workflow.SignalWithStartWorkflowRequest request) { - io.temporal.workflow.SignalWithStartWorkflowResponse result = (io.temporal.workflow.SignalWithStartWorkflowResponse) io.temporal.workflow.Workflow.newUntypedNexusServiceStub("temporal.api.workflowservice.v1.WorkflowService", io.temporal.workflow.NexusServiceOptions.newBuilder().setEndpoint("__temporal_system").build()).execute("SignalWithStartWorkflowExecution", io.temporal.workflow.SignalWithStartWorkflowResponse.class, io.temporal.workflow.SignalWithStartWorkflowResponse.class, request); - return io.temporal.workflow.Workflow.newUntypedExternalWorkflowStub(io.temporal.api.common.v1.WorkflowExecution.newBuilder().setWorkflowId(request.getId()).setRunId(result.getRunId() == null ? "" : result.getRunId()).build()); + + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.SignalWithStartWorkflowRequest request) { + io.temporal.workflow.SignalWithStartWorkflowResponse result = + (io.temporal.workflow.SignalWithStartWorkflowResponse) + io.temporal.workflow.Workflow.newUntypedNexusServiceStub( + "temporal.api.workflowservice.v1.WorkflowService", + io.temporal.workflow.NexusServiceOptions.newBuilder() + .setEndpoint("__temporal_system") + .build()) + .execute( + "SignalWithStartWorkflowExecution", + io.temporal.workflow.SignalWithStartWorkflowResponse.class, + io.temporal.workflow.SignalWithStartWorkflowResponse.class, + request); + return io.temporal.workflow.Workflow.newUntypedExternalWorkflowStub( + io.temporal.api.common.v1.WorkflowExecution.newBuilder() + .setWorkflowId(request.getId()) + .setRunId(result.getRunId() == null ? "" : result.getRunId()) + .build()); + } + + public static io.temporal.payload.context.SerializationContext + signalWithStartWorkflowSerializationContext( + io.temporal.workflow.SignalWithStartWorkflowRequest request) { + return io.temporal.internal.nexus.system.TemporalModelConverters + .signalWithStartWorkflowSerializationContext(request); + } + + public static T withDataConverter( + io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { + return io.temporal.workflow.NexgenRuntime.withDataConverter(converter, action); } - public static io.temporal.payload.context.SerializationContext signalWithStartWorkflowSerializationContext(io.temporal.workflow.SignalWithStartWorkflowRequest request) { return io.temporal.internal.nexus.system.TemporalModelConverters.signalWithStartWorkflowSerializationContext(request); } - public static T withDataConverter(io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { return io.temporal.workflow.NexgenRuntime.withDataConverter(converter, action); } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java index f7b8a4996a..5f341628fd 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowService.java @@ -4,5 +4,6 @@ @io.nexusrpc.Service(name = "temporal.api.workflowservice.v1.WorkflowService") public interface WorkflowService { @io.nexusrpc.Operation(name = "SignalWithStartWorkflowExecution") - io.temporal.workflow.SignalWithStartWorkflowResponse signalWithStartWorkflow(io.temporal.workflow.SignalWithStartWorkflowRequest request); + io.temporal.workflow.SignalWithStartWorkflowResponse signalWithStartWorkflow( + io.temporal.workflow.SignalWithStartWorkflowRequest request); } diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index 2a1cbd3c4a..5f01697742 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -26,6 +26,11 @@ from operation input/output protobuf transfer types. The service client's Java payload visitor generator consumes it, including payload-free response roots, without depending on compiled SDK classes. +Regeneration passes `--format` to nex-gen, which uses google-java-format 1.24.0 +to match the SDK's Spotless configuration. Nex-gen downloads and caches its +standalone JAR on first use; for offline regeneration, set +`NEXGEN_JAVA_FORMAT_JAR` to a local all-dependencies JAR. A JDK must be on `PATH`. + `TemporalModelConverters` contains the SDK-owned conversion helpers. The emitted `NexgenRuntime` contains common generated Java code and is rendered from a Rust string in nex-gen. Normal Java SDK builds do not require Rust or nex-gen. From 8dd88e665e724eebad913221bb37a9e4d006fc8d Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Tue, 20 Oct 2026 09:11:52 -0700 Subject: [PATCH 06/17] Keep generated model converter scoping in SDK internals --- .../io/temporal/workflow/NexgenRuntime.java | 301 +----------------- .../SignalWithStartWorkflowRequest.java | 219 ++++--------- .../SignalWithStartWorkflowResponse.java | 15 +- .../io/temporal/workflow/UserMetadata.java | 27 +- .../temporal/workflow/WorkflowOperations.java | 12 - .../system/SystemNexusDataConverter.java | 27 +- .../nexus/system/TemporalModelConverters.java | 5 + temporal-sdk/src/main/nexus/README.md | 9 +- .../system/SystemNexusDataConverterTest.java | 47 ++- 9 files changed, 168 insertions(+), 494 deletions(-) diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java index 540b91d8db..7fd49cfaa1 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java @@ -1,306 +1,19 @@ // Generated by nexgen. DO NOT EDIT! package io.temporal.workflow; -/** Shared conversion helpers for generated WIT models. */ +/** Shared conversion helpers used by these generated models. */ @SuppressWarnings({"unchecked", "rawtypes"}) public final class NexgenRuntime { private NexgenRuntime() {} - private static final ThreadLocal CONVERTER = - new ThreadLocal<>(); - - public static io.temporal.common.converter.DataConverter dataConverter() { - io.temporal.common.converter.DataConverter value = CONVERTER.get(); - return value == null - ? io.temporal.common.converter.DefaultDataConverter.STANDARD_INSTANCE - : value; - } - - public static T withDataConverter( - io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { - io.temporal.common.converter.DataConverter previous = CONVERTER.get(); - CONVERTER.set(converter); - try { - return action.get(); - } finally { - if (previous == null) CONVERTER.remove(); - else CONVERTER.set(previous); - } - } - - public static java.lang.reflect.Type parameterized( - final Class raw, final java.lang.reflect.Type... arguments) { - return new java.lang.reflect.ParameterizedType() { - public java.lang.reflect.Type getRawType() { - return raw; - } - - public java.lang.reflect.Type getOwnerType() { - return raw.getDeclaringClass(); - } - - public java.lang.reflect.Type[] getActualTypeArguments() { - return arguments.clone(); - } - }; - } - - public static java.lang.reflect.Type argument(java.lang.reflect.Type type, int index) { - return type instanceof java.lang.reflect.ParameterizedType - ? ((java.lang.reflect.ParameterizedType) type).getActualTypeArguments()[index] - : Object.class; - } - - public static Object get(com.google.protobuf.Message message, String name) { - return message.getField(field(message, name)); - } - - public static boolean has(com.google.protobuf.Message message, String name) { - com.google.protobuf.Descriptors.FieldDescriptor field = field(message, name); - return field.isRepeated() ? message.getRepeatedFieldCount(field) > 0 : message.hasField(field); - } - - private static com.google.protobuf.Descriptors.FieldDescriptor field( - com.google.protobuf.MessageOrBuilder message, String name) { - com.google.protobuf.Descriptors.FieldDescriptor field = - message.getDescriptorForType().findFieldByName(name); - if (field == null) throw new IllegalArgumentException("Unknown protobuf field: " + name); - return field; - } - - public static void set(com.google.protobuf.Message.Builder builder, String name, Object value) { - com.google.protobuf.Descriptors.FieldDescriptor field = field(builder, name); - if (field.isMapField() && value instanceof java.util.Map) { - for (Object raw : ((java.util.Map) value).entrySet()) { - java.util.Map.Entry entry = (java.util.Map.Entry) raw; - com.google.protobuf.Message.Builder entryBuilder = builder.newBuilderForField(field); - set(entryBuilder, "key", entry.getKey()); - set(entryBuilder, "value", entry.getValue()); - builder.addRepeatedField(field, entryBuilder.build()); - } - } else if (field.isRepeated()) { - java.util.List normalized = new java.util.ArrayList<>(); - for (Object item : (java.util.List) value) normalized.add(wireValue(field, item)); - builder.setField(field, normalized); - } else { - builder.setField(field, wireValue(field, value)); - } - } - - private static Object wireValue( - com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { - if (field.getJavaType() == com.google.protobuf.Descriptors.FieldDescriptor.JavaType.ENUM) { - if (value instanceof String) { - String name = (String) value; - com.google.protobuf.Descriptors.EnumValueDescriptor member = - field.getEnumType().findValueByName(name); - if (member != null) return member; - for (com.google.protobuf.Descriptors.EnumValueDescriptor candidate : - field.getEnumType().getValues()) - if (candidate.getName().endsWith("_" + name)) return candidate; - throw new IllegalArgumentException("Unknown enum value: " + name); - } - if (value instanceof Number) - return field.getEnumType().findValueByNumberCreatingIfUnknown(((Number) value).intValue()); - if (value instanceof com.google.protobuf.ProtocolMessageEnum) - return ((com.google.protobuf.ProtocolMessageEnum) value).getValueDescriptor(); - } - if (value instanceof Number) { - switch (field.getJavaType()) { - case INT: - return ((Number) value).intValue(); - case LONG: - return ((Number) value).longValue(); - case FLOAT: - return ((Number) value).floatValue(); - case DOUBLE: - return ((Number) value).doubleValue(); - default: - break; - } - } - return value; - } - - public static java.util.Map protoMap(Object value) { - java.util.Map result = new java.util.LinkedHashMap<>(); - for (com.google.protobuf.Message entry : (java.util.List) value) - result.put(get(entry, "key"), get(entry, "value")); - return result; - } - - public static java.util.List map( - java.util.List values, java.util.function.Function function) { - java.util.List result = new java.util.ArrayList<>(values.size()); - for (A value : values) result.add(function.apply(value)); - return result; - } - - public static java.util.Map mapValues( - java.util.Map values, - java.util.function.Function key, - java.util.function.Function value) { - java.util.Map result = new java.util.LinkedHashMap<>(); - for (java.util.Map.Entry entry : values.entrySet()) - result.put(key.apply(entry.getKey()), value.apply(entry.getValue())); - return result; - } - - public static final class FunctionReference { - private final F callable; - private final N name; - - private FunctionReference(F callable, N name) { - this.callable = callable; - this.name = name; - } - - public static FunctionReference callable(F value) { - return new FunctionReference<>(java.util.Objects.requireNonNull(value), null); - } - - public static FunctionReference named(N value) { - return new FunctionReference<>(null, java.util.Objects.requireNonNull(value)); - } - - public boolean isNamed() { - return name != null; - } - - public F getCallable() { - return callable; - } - - public N getName() { - return name; - } - } - - public interface Flag { - long getBit(); - } - - public static long flags(java.util.Set> values) { - long result = 0; - for (Enum value : values) result |= ((Flag) value).getBit(); - return result; - } - - public static & Flag> java.util.EnumSet flagsFromNumber( - long bits, Class type) { - java.util.EnumSet result = java.util.EnumSet.noneOf(type); - for (E value : type.getEnumConstants()) if ((bits & value.getBit()) != 0) result.add(value); - return result; - } - - public static Object decode( - Object value, - io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type type) { - Class raw = - type instanceof Class - ? (Class) type - : type instanceof java.lang.reflect.ParameterizedType - ? (Class) ((java.lang.reflect.ParameterizedType) type).getRawType() - : Object.class; - if (value instanceof io.temporal.api.common.v1.Payload) - return converter.fromPayload((io.temporal.api.common.v1.Payload) value, raw, type); - io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; - return converter.fromPayloads(0, java.util.Optional.of(payloads), raw, type); - } - - public static java.util.List decodeSequence( - Object value, + public static java.util.List decodeSequence( + io.temporal.api.common.v1.Payloads payloads, io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type element) { - io.temporal.api.common.v1.Payloads payloads = (io.temporal.api.common.v1.Payloads) value; - Class raw = - element instanceof Class - ? (Class) element - : element instanceof java.lang.reflect.ParameterizedType - ? (Class) ((java.lang.reflect.ParameterizedType) element).getRawType() - : Object.class; - java.util.List result = new java.util.ArrayList<>(); + Class elementClass, + java.lang.reflect.Type elementType) { + java.util.List result = new java.util.ArrayList<>(); for (io.temporal.api.common.v1.Payload payload : payloads.getPayloadsList()) - result.add(converter.fromPayload(payload, raw, element)); + result.add(converter.fromPayload(payload, elementClass, elementType)); return result; } - - @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Result.Deserializer.class) - public static final class Result { - private final boolean ok; - private final Object value; - - private Result(boolean ok, Object value) { - this.ok = ok; - this.value = value; - } - - public static Result ok(O value) { - return new Result<>(true, value); - } - - public static Result err(E value) { - return new Result<>(false, value); - } - - @com.fasterxml.jackson.annotation.JsonIgnore - public boolean isOk() { - return ok; - } - - public String getTag() { - return ok ? "ok" : "err"; - } - - public Object getValue() { - return value; - } - - @com.fasterxml.jackson.annotation.JsonIgnore - public O getOk() { - if (!ok) throw new IllegalStateException("Error result"); - return (O) value; - } - - @com.fasterxml.jackson.annotation.JsonIgnore - public E getErr() { - if (ok) throw new IllegalStateException("Success result"); - return (E) value; - } - - public static final class Deserializer - extends com.fasterxml.jackson.databind.JsonDeserializer - implements com.fasterxml.jackson.databind.deser.ContextualDeserializer { - private final com.fasterxml.jackson.databind.JavaType type; - - public Deserializer() { - this(null); - } - - private Deserializer(com.fasterxml.jackson.databind.JavaType type) { - this.type = type; - } - - public com.fasterxml.jackson.databind.JsonDeserializer createContextual( - com.fasterxml.jackson.databind.DeserializationContext context, - com.fasterxml.jackson.databind.BeanProperty property) { - return new Deserializer(context.getContextualType()); - } - - public Result deserialize( - com.fasterxml.jackson.core.JsonParser parser, - com.fasterxml.jackson.databind.DeserializationContext context) - throws java.io.IOException { - com.fasterxml.jackson.databind.JsonNode node = parser.getCodec().readTree(parser); - String tag = node.get("tag").asText(); - if (!"ok".equals(tag) && !"err".equals(tag)) - throw new java.io.IOException("Unknown result tag: " + tag); - boolean ok = "ok".equals(tag); - Object value = - context.readTreeAsValue(node.get("value"), type.containedTypeOrUnknown(ok ? 0 : 1)); - return new Result(ok, value); - } - } - } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java index da32092827..e1bb6ed755 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java @@ -450,105 +450,74 @@ public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionReques io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder(); if (this.workflow != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "workflow_type", + proto.setWorkflowType( io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeToProto( converter, (this.workflow))); if (this.args != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "input", + proto.setInput( converter .toPayloads((this.args).toArray()) .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); - if (this.id != null) io.temporal.workflow.NexgenRuntime.set(proto, "workflow_id", (this.id)); + if (this.id != null) proto.setWorkflowId((this.id)); if (this.taskQueue != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "task_queue", + proto.setTaskQueue( io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueToProto( converter, (this.taskQueue))); - if (this.signal != null) - io.temporal.workflow.NexgenRuntime.set(proto, "signal_name", (this.signal)); + if (this.signal != null) proto.setSignalName((this.signal)); if (this.signalArgs != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "signal_input", + proto.setSignalInput( converter .toPayloads((this.signalArgs).toArray()) .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); if (this.executionTimeout != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "workflow_execution_timeout", + proto.setWorkflowExecutionTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( converter, (this.executionTimeout))); if (this.runTimeout != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "workflow_run_timeout", + proto.setWorkflowRunTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( converter, (this.runTimeout))); if (this.taskTimeout != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "workflow_task_timeout", + proto.setWorkflowTaskTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( converter, (this.taskTimeout))); if (this.idReusePolicy != null) - io.temporal.workflow.NexgenRuntime.set( - proto, "workflow_id_reuse_policy", (this.idReusePolicy).getNumber()); + proto.setWorkflowIdReusePolicy( + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( + (this.idReusePolicy).getNumber())); if (this.idConflictPolicy != null) - io.temporal.workflow.NexgenRuntime.set( - proto, "workflow_id_conflict_policy", (this.idConflictPolicy).getNumber()); + proto.setWorkflowIdConflictPolicy( + io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber( + (this.idConflictPolicy).getNumber())); if (this.retryPolicy != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "retry_policy", + proto.setRetryPolicy( io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyToProto( converter, (this.retryPolicy))); - if (this.cronSchedule != null) - io.temporal.workflow.NexgenRuntime.set(proto, "cron_schedule", (this.cronSchedule)); + if (this.cronSchedule != null) proto.setCronSchedule((this.cronSchedule)); if (this.memo != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "memo", + proto.setMemo( io.temporal.internal.nexus.system.TemporalModelConverters.memoToProto( converter, (this.memo))); if (this.searchAttributes != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "search_attributes", + proto.setSearchAttributes( io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesToProto( converter, (this.searchAttributes))); if (this.priority != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "priority", + proto.setPriority( io.temporal.internal.nexus.system.TemporalModelConverters.priorityToProto( converter, (this.priority))); if (this.versioningOverride != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "versioning_override", + proto.setVersioningOverride( io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideToProto( converter, (this.versioningOverride))); if (this.startDelay != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "workflow_start_delay", + proto.setWorkflowStartDelay( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( converter, (this.startDelay))); - if (this.userMetadata != null) - io.temporal.workflow.NexgenRuntime.set( - proto, "user_metadata", (this.userMetadata).toProto(converter)); - if (this.namespace != null) - io.temporal.workflow.NexgenRuntime.set(proto, "namespace", (this.namespace)); + if (this.userMetadata != null) proto.setUserMetadata((this.userMetadata).toProto(converter)); + if (this.namespace != null) proto.setNamespace((this.namespace)); if (this.headers != null) - io.temporal.workflow.NexgenRuntime.set( - proto, - "header", + proto.setHeader( io.temporal.internal.nexus.system.TemporalModelConverters.headerToProto( converter, (this.headers))); return proto.build(); @@ -559,127 +528,78 @@ public static SignalWithStartWorkflowRequest fromProto( io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { Builder builder = SignalWithStartWorkflowRequest.newBuilder(); - if (true) - builder.setWorkflow( - io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto( - converter, - (io.temporal.api.common.v1.WorkflowType) - io.temporal.workflow.NexgenRuntime.get(proto, "workflow_type"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "input")) + builder.setWorkflow( + io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto( + converter, proto.getWorkflowType())); + if (proto.hasInput()) builder.setArgs( (java.util.List) (Object) io.temporal.workflow.NexgenRuntime.decodeSequence( - io.temporal.workflow.NexgenRuntime.get(proto, "input"), - converter, - io.temporal.workflow.NexgenRuntime.argument( - new com.fasterxml.jackson.core.type.TypeReference< - java.util.List>() {}.getType(), - 0))); - if (true) builder.setId((String) io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id")); - if (true) - builder.setTaskQueue( - io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto( - converter, - (io.temporal.api.taskqueue.v1.TaskQueue) - io.temporal.workflow.NexgenRuntime.get(proto, "task_queue"))); - if (true) - builder.setSignal((String) io.temporal.workflow.NexgenRuntime.get(proto, "signal_name")); - if (io.temporal.workflow.NexgenRuntime.has(proto, "signal_input")) + proto.getInput(), converter, Object.class, Object.class)); + builder.setId(proto.getWorkflowId()); + builder.setTaskQueue( + io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto( + converter, proto.getTaskQueue())); + builder.setSignal(proto.getSignalName()); + if (proto.hasSignalInput()) builder.setSignalArgs( (java.util.List) (Object) io.temporal.workflow.NexgenRuntime.decodeSequence( - io.temporal.workflow.NexgenRuntime.get(proto, "signal_input"), - converter, - io.temporal.workflow.NexgenRuntime.argument( - new com.fasterxml.jackson.core.type.TypeReference< - java.util.List>() {}.getType(), - 0))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_execution_timeout")) + proto.getSignalInput(), converter, Object.class, Object.class)); + if (proto.hasWorkflowExecutionTimeout()) builder.setExecutionTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, - (com.google.protobuf.Duration) - io.temporal.workflow.NexgenRuntime.get(proto, "workflow_execution_timeout"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_run_timeout")) + converter, proto.getWorkflowExecutionTimeout())); + if (proto.hasWorkflowRunTimeout()) builder.setRunTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, - (com.google.protobuf.Duration) - io.temporal.workflow.NexgenRuntime.get(proto, "workflow_run_timeout"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_task_timeout")) + converter, proto.getWorkflowRunTimeout())); + if (proto.hasWorkflowTaskTimeout()) builder.setTaskTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, - (com.google.protobuf.Duration) - io.temporal.workflow.NexgenRuntime.get(proto, "workflow_task_timeout"))); - if (true) - builder.setIdReusePolicy( - io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( - ((com.google.protobuf.Descriptors.EnumValueDescriptor) - io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id_reuse_policy")) - .getNumber())); - if (true) - builder.setIdConflictPolicy( - io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber( - ((com.google.protobuf.Descriptors.EnumValueDescriptor) - io.temporal.workflow.NexgenRuntime.get(proto, "workflow_id_conflict_policy")) - .getNumber())); - if (io.temporal.workflow.NexgenRuntime.has(proto, "retry_policy")) + converter, proto.getWorkflowTaskTimeout())); + builder.setIdReusePolicy( + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( + (proto.getWorkflowIdReusePolicy()).getNumber())); + builder.setIdConflictPolicy( + io.temporal.api.enums.v1.WorkflowIdConflictPolicy.forNumber( + (proto.getWorkflowIdConflictPolicy()).getNumber())); + if (proto.hasRetryPolicy()) builder.setRetryPolicy( io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyFromProto( - converter, - (io.temporal.api.common.v1.RetryPolicy) - io.temporal.workflow.NexgenRuntime.get(proto, "retry_policy"))); - if (true) - builder.setCronSchedule( - (String) io.temporal.workflow.NexgenRuntime.get(proto, "cron_schedule")); - if (io.temporal.workflow.NexgenRuntime.has(proto, "memo")) + converter, proto.getRetryPolicy())); + builder.setCronSchedule(proto.getCronSchedule()); + if (proto.hasMemo()) builder.setMemo( io.temporal.internal.nexus.system.TemporalModelConverters.memoFromProto( - converter, - (io.temporal.api.common.v1.Memo) - io.temporal.workflow.NexgenRuntime.get(proto, "memo"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "search_attributes")) + converter, proto.getMemo())); + if (proto.hasSearchAttributes()) builder.setSearchAttributes( io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesFromProto( - converter, - (io.temporal.api.common.v1.SearchAttributes) - io.temporal.workflow.NexgenRuntime.get(proto, "search_attributes"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "priority")) + converter, proto.getSearchAttributes())); + if (proto.hasPriority()) builder.setPriority( io.temporal.internal.nexus.system.TemporalModelConverters.priorityFromProto( - converter, - (io.temporal.api.common.v1.Priority) - io.temporal.workflow.NexgenRuntime.get(proto, "priority"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "versioning_override")) + converter, proto.getPriority())); + if (proto.hasVersioningOverride()) builder.setVersioningOverride( io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideFromProto( - converter, - (io.temporal.api.workflow.v1.VersioningOverride) - io.temporal.workflow.NexgenRuntime.get(proto, "versioning_override"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "workflow_start_delay")) + converter, proto.getVersioningOverride())); + if (proto.hasWorkflowStartDelay()) builder.setStartDelay( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, - (com.google.protobuf.Duration) - io.temporal.workflow.NexgenRuntime.get(proto, "workflow_start_delay"))); - if (io.temporal.workflow.NexgenRuntime.has(proto, "user_metadata")) + converter, proto.getWorkflowStartDelay())); + if (proto.hasUserMetadata()) builder.setUserMetadata( io.temporal.workflow.UserMetadata.fromProto( - (io.temporal.api.sdk.v1.UserMetadata) - io.temporal.workflow.NexgenRuntime.get(proto, "user_metadata"), - converter, - io.temporal.workflow.UserMetadata.class)); - if (true) - builder.setNamespace((String) io.temporal.workflow.NexgenRuntime.get(proto, "namespace")); - if (io.temporal.workflow.NexgenRuntime.has(proto, "header")) + proto.getUserMetadata(), converter, io.temporal.workflow.UserMetadata.class)); + builder.setNamespace(proto.getNamespace()); + if (proto.hasHeader()) builder.setHeaders( io.temporal.internal.nexus.system.TemporalModelConverters.headerFromProto( - converter, - (io.temporal.api.common.v1.Header) - io.temporal.workflow.NexgenRuntime.get(proto, "header"))); + converter, proto.getHeader())); return builder.build(); } @@ -693,7 +613,8 @@ public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) public Object toTransferType(SignalWithStartWorkflowRequest value) { return value == null ? null - : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); + : value.toProto( + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); } public SignalWithStartWorkflowRequest fromTransferType( @@ -702,7 +623,7 @@ public SignalWithStartWorkflowRequest fromTransferType( ? null : fromProto( (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value, - io.temporal.workflow.NexgenRuntime.dataConverter(), + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), valueType); } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java index e8bbb8827a..a433bec3b8 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java @@ -72,9 +72,8 @@ public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRespon io.temporal.common.converter.DataConverter converter) { io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); - if (this.runId != null) io.temporal.workflow.NexgenRuntime.set(proto, "run_id", (this.runId)); - if (this.started != null) - io.temporal.workflow.NexgenRuntime.set(proto, "started", (this.started)); + if (this.runId != null) proto.setRunId((this.runId)); + if (this.started != null) proto.setStarted((this.started)); return proto.build(); } @@ -83,9 +82,8 @@ public static SignalWithStartWorkflowResponse fromProto( io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { Builder builder = SignalWithStartWorkflowResponse.newBuilder(); - if (true) builder.setRunId((String) io.temporal.workflow.NexgenRuntime.get(proto, "run_id")); - if (true) - builder.setStarted((Boolean) io.temporal.workflow.NexgenRuntime.get(proto, "started")); + builder.setRunId(proto.getRunId()); + builder.setStarted(proto.getStarted()); return builder.build(); } @@ -99,7 +97,8 @@ public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) public Object toTransferType(SignalWithStartWorkflowResponse value) { return value == null ? null - : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); + : value.toProto( + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); } public SignalWithStartWorkflowResponse fromTransferType( @@ -108,7 +107,7 @@ public SignalWithStartWorkflowResponse fromTransferType( ? null : fromProto( (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value, - io.temporal.workflow.NexgenRuntime.dataConverter(), + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), valueType); } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java index ded8735e64..5f46870136 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java @@ -79,11 +79,9 @@ public io.temporal.api.sdk.v1.UserMetadata toProto( io.temporal.api.sdk.v1.UserMetadata.Builder proto = io.temporal.api.sdk.v1.UserMetadata.newBuilder(); if (this.staticSummary != null) - io.temporal.workflow.NexgenRuntime.set( - proto, "summary", converter.toPayload((this.staticSummary)).get()); + proto.setSummary(converter.toPayload((this.staticSummary)).get()); if (this.staticDetails != null) - io.temporal.workflow.NexgenRuntime.set( - proto, "details", converter.toPayload((this.staticDetails)).get()); + proto.setDetails(converter.toPayload((this.staticDetails)).get()); return proto.build(); } @@ -92,20 +90,12 @@ public static UserMetadata fromProto( io.temporal.common.converter.DataConverter converter, java.lang.reflect.Type modelType) { Builder builder = UserMetadata.newBuilder(); - if (io.temporal.workflow.NexgenRuntime.has(proto, "summary")) + if (proto.hasSummary()) builder.setStaticSummary( - (Object) - io.temporal.workflow.NexgenRuntime.decode( - io.temporal.workflow.NexgenRuntime.get(proto, "summary"), - converter, - Object.class)); - if (io.temporal.workflow.NexgenRuntime.has(proto, "details")) + (Object) converter.fromPayload(proto.getSummary(), Object.class, Object.class)); + if (proto.hasDetails()) builder.setStaticDetails( - (Object) - io.temporal.workflow.NexgenRuntime.decode( - io.temporal.workflow.NexgenRuntime.get(proto, "details"), - converter, - Object.class)); + (Object) converter.fromPayload(proto.getDetails(), Object.class, Object.class)); return builder.build(); } @@ -118,7 +108,8 @@ public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) public Object toTransferType(UserMetadata value) { return value == null ? null - : value.toProto(io.temporal.workflow.NexgenRuntime.dataConverter()); + : value.toProto( + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); } public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueType) { @@ -126,7 +117,7 @@ public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueT ? null : fromProto( (io.temporal.api.sdk.v1.UserMetadata) value, - io.temporal.workflow.NexgenRuntime.dataConverter(), + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), valueType); } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java index 529c09852e..a6d15268b3 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java @@ -25,16 +25,4 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( .setRunId(result.getRunId() == null ? "" : result.getRunId()) .build()); } - - public static io.temporal.payload.context.SerializationContext - signalWithStartWorkflowSerializationContext( - io.temporal.workflow.SignalWithStartWorkflowRequest request) { - return io.temporal.internal.nexus.system.TemporalModelConverters - .signalWithStartWorkflowSerializationContext(request); - } - - public static T withDataConverter( - io.temporal.common.converter.DataConverter converter, java.util.function.Supplier action) { - return io.temporal.workflow.NexgenRuntime.withDataConverter(converter, action); - } } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java index fb0f7fe14a..7a420b642b 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java @@ -9,16 +9,37 @@ import io.temporal.common.converter.RawValue; import io.temporal.internal.common.converter.TemporalTransferTypeDataConverter; import io.temporal.internal.payload.visitor.SystemNexusPayloads; -import io.temporal.workflow.NexgenRuntime; import java.lang.reflect.Type; +import java.util.Objects; import java.util.Optional; +import java.util.function.Supplier; import javax.annotation.Nonnull; /** Keeps the server-readable envelope separate from the destination workflow's user converter. */ public final class SystemNexusDataConverter implements DataConverter { public static final String ENDPOINT = "__temporal_system"; + private static final ThreadLocal USER_CONVERTER = new ThreadLocal<>(); private final DataConverter userConverter; + static DataConverter currentDataConverter() { + DataConverter converter = USER_CONVERTER.get(); + if (converter == null) + throw new IllegalStateException("System Nexus user converter context is not active"); + return converter; + } + + static T withDataConverter(DataConverter converter, Supplier action) { + Objects.requireNonNull(converter, "converter"); + DataConverter previous = USER_CONVERTER.get(); + USER_CONVERTER.set(converter); + try { + return action.get(); + } finally { + if (previous == null) USER_CONVERTER.remove(); + else USER_CONVERTER.set(previous); + } + } + public SystemNexusDataConverter(DataConverter userConverter) { this.userConverter = userConverter; } @@ -26,7 +47,7 @@ public SystemNexusDataConverter(DataConverter userConverter) { @Override public Optional toPayload(T value) { if (value instanceof RawValue) return Optional.of(((RawValue) value).getPayload()); - return NexgenRuntime.withDataConverter( + return withDataConverter( userConverter, () -> { Object transferred = TemporalTransferTypeDataConverter.toTransferValue(value); @@ -40,7 +61,7 @@ public Optional toPayload(T value) { @Override public T fromPayload(Payload payload, Class valueClass, Type valueType) { if (valueClass == RawValue.class) return valueClass.cast(new RawValue(payload)); - return NexgenRuntime.withDataConverter( + return withDataConverter( userConverter, () -> { Message value = SystemNexusPayloads.unpack(payload).build(); diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java index 329fce0b92..57825ebcef 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -17,6 +17,11 @@ public final class TemporalModelConverters { private TemporalModelConverters() {} + /** Returns the user converter active during system Nexus transfer conversion. */ + public static DataConverter currentDataConverter() { + return SystemNexusDataConverter.currentDataConverter(); + } + public static String workflowNamespace() { return Workflow.getInfo().getNamespace(); } diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index 5f01697742..513a634961 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -32,5 +32,10 @@ standalone JAR on first use; for offline regeneration, set `NEXGEN_JAVA_FORMAT_JAR` to a local all-dependencies JAR. A JDK must be on `PATH`. `TemporalModelConverters` contains the SDK-owned conversion helpers. The emitted -`NexgenRuntime` contains common generated Java code and is rendered from a Rust -string in nex-gen. Normal Java SDK builds do not require Rust or nex-gen. +`NexgenRuntime` contains only payload-sequence decoding. Converter scoping lives +in `SystemNexusDataConverter`; generated transfer converters obtain the active +converter through `TemporalModelConverters.currentDataConverter()` and fail +when no scope is active, matching Python. Protobuf field access is generated +directly. Nex-gen assembles the required +runtime helpers from Rust strings. Normal Java SDK builds do not require Rust +or nex-gen. diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java index 1d16ba755d..74a10adbb3 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java @@ -135,16 +135,47 @@ public void responseAndRawValuesRoundTripAndConverterScopesRestore() { SignalWithStartWorkflowResponse.class) .getRunId()); assertSame(encoded, converter.toPayload(new RawValue(encoded)).get()); - DataConverter original = NexgenRuntime.dataConverter(); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + } + + @Test + public void converterScopesRestoreAfterNestedFailure() { + DataConverter outer = DefaultDataConverter.STANDARD_INSTANCE; + DataConverter inner = new DefaultDataConverter(); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + SystemNexusDataConverter.withDataConverter( + outer, + () -> { + assertSame(outer, TemporalModelConverters.currentDataConverter()); + assertThrows( + IllegalArgumentException.class, + () -> + SystemNexusDataConverter.withDataConverter( + inner, + () -> { + assertSame(inner, TemporalModelConverters.currentDataConverter()); + throw new IllegalArgumentException("test"); + })); + assertSame(outer, TemporalModelConverters.currentDataConverter()); + return null; + }); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + } + + @Test + public void transferConversionRequiresActiveUserConverter() { + SignalWithStartWorkflowRequest.Converter converter = + new SignalWithStartWorkflowRequest.Converter(); + IllegalStateException encodeFailure = + assertThrows( + IllegalStateException.class, () -> converter.toTransferType(request("target"))); + assertEquals("System Nexus user converter context is not active", encodeFailure.getMessage()); assertThrows( IllegalStateException.class, () -> - NexgenRuntime.withDataConverter( - converter, - () -> { - throw new IllegalStateException("test"); - })); - assertSame(original, NexgenRuntime.dataConverter()); + converter.fromTransferType( + SignalWithStartWorkflowExecutionRequest.getDefaultInstance(), + SignalWithStartWorkflowRequest.class)); } @Test @@ -181,7 +212,7 @@ public void operationsRetainIndependentDestinationConverters() { SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class) .getId()); - assertSame(DefaultDataConverter.STANDARD_INSTANCE, NexgenRuntime.dataConverter()); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); } @Test From c7c7443c0fb330c7e005241df3c2ed0811948fd7 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Tue, 20 Oct 2026 09:22:48 -0700 Subject: [PATCH 07/17] Keep system envelope handling out of CodecDataConverter --- .../common/converter/CodecDataConverter.java | 34 ++++++------------ temporal-sdk/src/main/nexus/README.md | 11 ++++-- .../system/SystemNexusDataConverterTest.java | 35 +++++++++++++------ 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/temporal-sdk/src/main/java/io/temporal/common/converter/CodecDataConverter.java b/temporal-sdk/src/main/java/io/temporal/common/converter/CodecDataConverter.java index bc0a15021c..a82172348b 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/converter/CodecDataConverter.java +++ b/temporal-sdk/src/main/java/io/temporal/common/converter/CodecDataConverter.java @@ -113,14 +113,18 @@ public CodecDataConverter( public Optional toPayload(T value) { Optional payload = ConverterUtils.withContext(dataConverter, serializationContext).toPayload(value); - List encodedPayloads = encode(Collections.singletonList(payload.get())); + List encodedPayloads = + ConverterUtils.withContext(chainCodec, serializationContext) + .encode(Collections.singletonList(payload.get())); Preconditions.checkState(encodedPayloads.size() == 1, "Expected one encoded payload"); return Optional.of(encodedPayloads.get(0)); } @Override public T fromPayload(Payload payload, Class valueClass, Type valueType) { - List decodedPayload = decode(Collections.singletonList(payload)); + List decodedPayload = + ConverterUtils.withContext(chainCodec, serializationContext) + .decode(Collections.singletonList(payload)); Preconditions.checkState(decodedPayload.size() == 1, "Expected one decoded payload"); return ConverterUtils.withContext(dataConverter, serializationContext) .fromPayload(decodedPayload.get(0), valueClass, valueType); @@ -131,7 +135,9 @@ public Optional toPayloads(Object... values) throws DataConverterExcep Optional payloads = ConverterUtils.withContext(dataConverter, serializationContext).toPayloads(values); if (payloads.isPresent()) { - List encodedPayloads = encode(payloads.get().getPayloadsList()); + List encodedPayloads = + ConverterUtils.withContext(chainCodec, serializationContext) + .encode(payloads.get().getPayloadsList()); payloads = Optional.of(Payloads.newBuilder().addAllPayloads(encodedPayloads).build()); } return payloads; @@ -187,31 +193,13 @@ public CodecDataConverter withContext(@Nonnull SerializationContext context) { @Nonnull @Override public List encode(@Nonnull List payloads) { - return visitSystemEnvelopes(payloads, true); + return ConverterUtils.withContext(chainCodec, serializationContext).encode(payloads); } @Nonnull @Override public List decode(@Nonnull List payloads) { - return visitSystemEnvelopes(payloads, false); - } - - private List visitSystemEnvelopes(List payloads, boolean encode) { - PayloadCodec codec = ConverterUtils.withContext(chainCodec, serializationContext); - if (payloads.stream() - .noneMatch(io.temporal.internal.payload.visitor.SystemNexusPayloads::isSystemPayload)) { - return encode ? codec.encode(payloads) : codec.decode(payloads); - } - return io.temporal.internal.payload.visitor.PayloadVisitors.visit( - Payloads.newBuilder().addAllPayloads(payloads).build(), - io.temporal.internal.payload.visitor.PayloadVisitorOptions.newBuilder( - (context, nested) -> - java.util.concurrent.CompletableFuture.completedFuture( - encode ? codec.encode(nested) : codec.decode(nested))) - .setSkipSearchAttributes(true) - .build()) - .join() - .getPayloadsList(); + return ConverterUtils.withContext(chainCodec, serializationContext).decode(payloads); } private Failure.Builder encodeFailure(Failure.Builder failure) { diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index 513a634961..79855f808f 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -36,6 +36,11 @@ standalone JAR on first use; for offline regeneration, set in `SystemNexusDataConverter`; generated transfer converters obtain the active converter through `TemporalModelConverters.currentDataConverter()` and fail when no scope is active, matching Python. Protobuf field access is generated -directly. Nex-gen assembles the required -runtime helpers from Rust strings. Normal Java SDK builds do not require Rust -or nex-gen. +directly. Nex-gen assembles the required runtime helpers from Rust strings. +Normal Java SDK builds do not require Rust or nex-gen. + +The SDK wraps any configured `DataConverter` in `SystemNexusDataConverter` for +system operations. That wrapper handles the outer envelope and delegates nested +user conversion; custom converters do not need to recognize system envelopes. +The shared payload visitor descends into marked envelopes for payload traversal. +`CodecDataConverter` contains no system Nexus handling. diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java index 74a10adbb3..04fedd2700 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java @@ -1,6 +1,8 @@ package io.temporal.internal.nexus.system; import static org.junit.Assert.*; +import static org.mockito.AdditionalAnswers.delegatesTo; +import static org.mockito.Mockito.*; import com.google.protobuf.ByteString; import io.temporal.api.common.v1.Payload; @@ -105,18 +107,29 @@ public void nestedPayloadsUseDestinationContextAndOuterEnvelopeBypassesCodecs() } @Test - public void codecsVisitNestedPayloadsInsideRawSystemEnvelopes() { + public void customDataConverterReceivesUserValuesWithoutSystemEnvelopeHandling() + throws Exception { SignalWithStartWorkflowRequest request = request("target"); - CodecDataConverter user = - new CodecDataConverter( - DefaultDataConverter.STANDARD_INSTANCE, - Collections.singletonList(new ContextCodec("target"))); - Payload plain = - new SystemNexusDataConverter(DefaultDataConverter.STANDARD_INSTANCE) - .toPayload(request) - .get(); - Payload encoded = user.encode(Collections.singletonList(plain)).get(0); - assertEquals(plain, user.decode(Collections.singletonList(encoded)).get(0)); + DataConverter user = + mock(DataConverter.class, delegatesTo(DefaultDataConverter.STANDARD_INSTANCE)); + SystemNexusDataConverter converter = new SystemNexusDataConverter(user); + Payload encoded = converter.toPayload(request).get(); + assertTrue(SystemNexusPayloads.isSystemPayload(encoded)); + SignalWithStartWorkflowExecutionRequest wire = + SignalWithStartWorkflowExecutionRequest.parseFrom(encoded.getData()); + assertEquals("target", wire.getWorkflowId()); + verify(user).toPayloads("workflow", 42); + verify(user).toPayloads("signal"); + verify(user).toPayload("value"); + verify(user, never()).toPayload(request); + verify(user, never()).toPayload(isA(com.google.protobuf.Message.class)); + SignalWithStartWorkflowRequest decoded = + converter.fromPayload( + encoded, SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class); + assertEquals(request.getArgs(), decoded.getArgs()); + assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); + assertEquals(request.getMemo(), decoded.getMemo()); + assertEquals(request.getHeaders(), decoded.getHeaders()); } @Test From dd65bc877d2210f59e9960725bb8987278915bb5 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Tue, 20 Oct 2026 10:43:05 -0700 Subject: [PATCH 08/17] Preserve serialized embedded payloads in system Nexus models --- CHANGELOG.md | 6 +- .../io/temporal/workflow/NexgenRuntime.java | 19 -- .../SignalWithStartWorkflowRequest.java | 169 ++++++----------- .../SignalWithStartWorkflowResponse.java | 16 +- .../io/temporal/workflow/UserMetadata.java | 56 ++---- .../system/SystemNexusDataConverter.java | 56 ++---- .../nexus/system/TemporalModelConverters.java | 109 ++--------- temporal-sdk/src/main/nexus/README.md | 17 +- .../src/main/nexus/SIGNAL_WITH_START.md | 42 ++-- .../nexus/deps/nexus-temporal-types/model.wit | 24 +-- .../system/SystemNexusDataConverterTest.java | 179 ++++++++++++------ .../nexus/SignalWithStartWorkflowTest.java | 21 +- .../SystemSignalWithStartIntegrationTest.java | 9 +- 13 files changed, 303 insertions(+), 420 deletions(-) delete mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f3e5554dd9..580ac40bd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,8 +31,10 @@ to docs, or any other relevant information. - Workflows can signal with start through the system workflow service using generated `Workflow.signalWithStartWorkflow(SignalWithStartWorkflowRequest)` API. Request builders and operations are generated into `io.temporal.workflow`. - System Nexus envelopes preserve destination workflow serialization context for nested payloads, - codecs, and external payload storage. Requires a server supporting the system workflow service. + Request models carry serialized protobuf payloads; API code serializes user values with the + destination workflow context before constructing the request. Transfer conversion preserves + opaque payload batches, and payload visitation supports external storage inside system envelopes. + Requires a server supporting the system workflow service. - Applications can use the experimental `@TransferTypeConvertible` annotation and `TransferTypeConverter` interface to convert top-level model values to transfer types. The SDK applies this conversion to workflow, activity, Nexus, and schedule payloads, including failure diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java deleted file mode 100644 index 7fd49cfaa1..0000000000 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java +++ /dev/null @@ -1,19 +0,0 @@ -// Generated by nexgen. DO NOT EDIT! -package io.temporal.workflow; - -/** Shared conversion helpers used by these generated models. */ -@SuppressWarnings({"unchecked", "rawtypes"}) -public final class NexgenRuntime { - private NexgenRuntime() {} - - public static java.util.List decodeSequence( - io.temporal.api.common.v1.Payloads payloads, - io.temporal.common.converter.DataConverter converter, - Class elementClass, - java.lang.reflect.Type elementType) { - java.util.List result = new java.util.ArrayList<>(); - for (io.temporal.api.common.v1.Payload payload : payloads.getPayloadsList()) - result.add(converter.fromPayload(payload, elementClass, elementType)); - return result; - } -} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java index e1bb6ed755..50d898f460 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java @@ -9,7 +9,7 @@ public final class SignalWithStartWorkflowRequest { private final String workflow; /** Arguments for the workflow. */ - private final java.util.List args; + private final io.temporal.api.common.v1.Payloads args; /** Unique identifier for the workflow execution. Must be nonempty. */ private final String id; @@ -20,7 +20,7 @@ public final class SignalWithStartWorkflowRequest { private final String signal; /** Arguments for the signal. */ - private final java.util.List signalArgs; + private final io.temporal.api.common.v1.Payloads signalArgs; /** * Total workflow execution timeout, including retries and continue-as-new. Defaults to unlimited. @@ -50,10 +50,10 @@ public final class SignalWithStartWorkflowRequest { private final String cronSchedule; /** Memo for the workflow. */ - private final java.util.Map memo; + private final io.temporal.api.common.v1.Memo memo; /** Typed search attributes for the workflow. */ - private final io.temporal.common.SearchAttributes searchAttributes; + private final io.temporal.api.common.v1.SearchAttributes searchAttributes; /** Priority of the workflow execution. */ private final io.temporal.common.Priority priority; @@ -71,17 +71,18 @@ public final class SignalWithStartWorkflowRequest { private final String namespace; /** Headers for the request. */ - private final java.util.Map headers; + private final io.temporal.api.common.v1.Header headers; @com.fasterxml.jackson.annotation.JsonCreator public SignalWithStartWorkflowRequest( @com.fasterxml.jackson.annotation.JsonProperty("workflow") String workflow, - @com.fasterxml.jackson.annotation.JsonProperty("args") java.util.List args, + @com.fasterxml.jackson.annotation.JsonProperty("args") + io.temporal.api.common.v1.Payloads args, @com.fasterxml.jackson.annotation.JsonProperty("id") String id, @com.fasterxml.jackson.annotation.JsonProperty("taskQueue") String taskQueue, @com.fasterxml.jackson.annotation.JsonProperty("signal") String signal, @com.fasterxml.jackson.annotation.JsonProperty("signalArgs") - java.util.List signalArgs, + io.temporal.api.common.v1.Payloads signalArgs, @com.fasterxml.jackson.annotation.JsonProperty("executionTimeout") java.time.Duration executionTimeout, @com.fasterxml.jackson.annotation.JsonProperty("runTimeout") java.time.Duration runTimeout, @@ -93,9 +94,9 @@ public SignalWithStartWorkflowRequest( @com.fasterxml.jackson.annotation.JsonProperty("retryPolicy") io.temporal.common.RetryOptions retryPolicy, @com.fasterxml.jackson.annotation.JsonProperty("cronSchedule") String cronSchedule, - @com.fasterxml.jackson.annotation.JsonProperty("memo") java.util.Map memo, + @com.fasterxml.jackson.annotation.JsonProperty("memo") io.temporal.api.common.v1.Memo memo, @com.fasterxml.jackson.annotation.JsonProperty("searchAttributes") - io.temporal.common.SearchAttributes searchAttributes, + io.temporal.api.common.v1.SearchAttributes searchAttributes, @com.fasterxml.jackson.annotation.JsonProperty("priority") io.temporal.common.Priority priority, @com.fasterxml.jackson.annotation.JsonProperty("versioningOverride") @@ -105,7 +106,7 @@ public SignalWithStartWorkflowRequest( io.temporal.workflow.UserMetadata userMetadata, @com.fasterxml.jackson.annotation.JsonProperty("namespace") String namespace, @com.fasterxml.jackson.annotation.JsonProperty("headers") - java.util.Map headers) { + io.temporal.api.common.v1.Header headers) { this.workflow = workflow; this.args = args; this.id = id; @@ -133,7 +134,7 @@ public String getWorkflow() { return workflow; } - public java.util.List getArgs() { + public io.temporal.api.common.v1.Payloads getArgs() { return args; } @@ -149,7 +150,7 @@ public String getSignal() { return signal; } - public java.util.List getSignalArgs() { + public io.temporal.api.common.v1.Payloads getSignalArgs() { return signalArgs; } @@ -181,11 +182,11 @@ public String getCronSchedule() { return cronSchedule; } - public java.util.Map getMemo() { + public io.temporal.api.common.v1.Memo getMemo() { return memo; } - public io.temporal.common.SearchAttributes getSearchAttributes() { + public io.temporal.api.common.v1.SearchAttributes getSearchAttributes() { return searchAttributes; } @@ -209,7 +210,7 @@ public String getNamespace() { return namespace; } - public java.util.Map getHeaders() { + public io.temporal.api.common.v1.Header getHeaders() { return headers; } @@ -260,9 +261,9 @@ public Builder setWorkflow(String value) { return this; } - private java.util.List args = null; + private io.temporal.api.common.v1.Payloads args = null; - public Builder setArgs(java.util.List value) { + public Builder setArgs(io.temporal.api.common.v1.Payloads value) { this.args = value; return this; } @@ -288,9 +289,9 @@ public Builder setSignal(String value) { return this; } - private java.util.List signalArgs = null; + private io.temporal.api.common.v1.Payloads signalArgs = null; - public Builder setSignalArgs(java.util.List value) { + public Builder setSignalArgs(io.temporal.api.common.v1.Payloads value) { this.signalArgs = value; return this; } @@ -345,16 +346,16 @@ public Builder setCronSchedule(String value) { return this; } - private java.util.Map memo = null; + private io.temporal.api.common.v1.Memo memo = null; - public Builder setMemo(java.util.Map value) { + public Builder setMemo(io.temporal.api.common.v1.Memo value) { this.memo = value; return this; } - private io.temporal.common.SearchAttributes searchAttributes = null; + private io.temporal.api.common.v1.SearchAttributes searchAttributes = null; - public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { + public Builder setSearchAttributes(io.temporal.api.common.v1.SearchAttributes value) { this.searchAttributes = value; return this; } @@ -394,14 +395,14 @@ public Builder setNamespace(String value) { return this; } - private java.util.Map headers = null; + private io.temporal.api.common.v1.Header headers = null; - public Builder setHeaders(java.util.Map value) { + public Builder setHeaders(io.temporal.api.common.v1.Header value) { this.headers = value; return this; } - public Builder setStaticSummary(Object value) { + public Builder setStaticSummary(io.temporal.api.common.v1.Payload value) { this.userMetadata = io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata) .setStaticSummary(value) @@ -409,7 +410,7 @@ public Builder setStaticSummary(Object value) { return this; } - public Builder setStaticDetails(Object value) { + public Builder setStaticDetails(io.temporal.api.common.v1.Payload value) { this.userMetadata = io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata) .setStaticDetails(value) @@ -445,42 +446,33 @@ public SignalWithStartWorkflowRequest build() { } } - public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto( - io.temporal.common.converter.DataConverter converter) { + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto() { io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder(); if (this.workflow != null) proto.setWorkflowType( io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeToProto( - converter, (this.workflow))); - if (this.args != null) - proto.setInput( - converter - .toPayloads((this.args).toArray()) - .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + (this.workflow))); + if (this.args != null) proto.setInput((this.args)); if (this.id != null) proto.setWorkflowId((this.id)); if (this.taskQueue != null) proto.setTaskQueue( io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueToProto( - converter, (this.taskQueue))); + (this.taskQueue))); if (this.signal != null) proto.setSignalName((this.signal)); - if (this.signalArgs != null) - proto.setSignalInput( - converter - .toPayloads((this.signalArgs).toArray()) - .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); + if (this.signalArgs != null) proto.setSignalInput((this.signalArgs)); if (this.executionTimeout != null) proto.setWorkflowExecutionTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - converter, (this.executionTimeout))); + (this.executionTimeout))); if (this.runTimeout != null) proto.setWorkflowRunTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - converter, (this.runTimeout))); + (this.runTimeout))); if (this.taskTimeout != null) proto.setWorkflowTaskTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - converter, (this.taskTimeout))); + (this.taskTimeout))); if (this.idReusePolicy != null) proto.setWorkflowIdReusePolicy( io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( @@ -492,74 +484,53 @@ public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionReques if (this.retryPolicy != null) proto.setRetryPolicy( io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyToProto( - converter, (this.retryPolicy))); + (this.retryPolicy))); if (this.cronSchedule != null) proto.setCronSchedule((this.cronSchedule)); - if (this.memo != null) - proto.setMemo( - io.temporal.internal.nexus.system.TemporalModelConverters.memoToProto( - converter, (this.memo))); - if (this.searchAttributes != null) - proto.setSearchAttributes( - io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesToProto( - converter, (this.searchAttributes))); + if (this.memo != null) proto.setMemo((this.memo)); + if (this.searchAttributes != null) proto.setSearchAttributes((this.searchAttributes)); if (this.priority != null) proto.setPriority( io.temporal.internal.nexus.system.TemporalModelConverters.priorityToProto( - converter, (this.priority))); + (this.priority))); if (this.versioningOverride != null) proto.setVersioningOverride( io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideToProto( - converter, (this.versioningOverride))); + (this.versioningOverride))); if (this.startDelay != null) proto.setWorkflowStartDelay( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - converter, (this.startDelay))); - if (this.userMetadata != null) proto.setUserMetadata((this.userMetadata).toProto(converter)); + (this.startDelay))); + if (this.userMetadata != null) proto.setUserMetadata((this.userMetadata).toProto()); if (this.namespace != null) proto.setNamespace((this.namespace)); - if (this.headers != null) - proto.setHeader( - io.temporal.internal.nexus.system.TemporalModelConverters.headerToProto( - converter, (this.headers))); + if (this.headers != null) proto.setHeader((this.headers)); return proto.build(); } public static SignalWithStartWorkflowRequest fromProto( - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto, - io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type modelType) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto) { Builder builder = SignalWithStartWorkflowRequest.newBuilder(); builder.setWorkflow( io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto( - converter, proto.getWorkflowType())); - if (proto.hasInput()) - builder.setArgs( - (java.util.List) - (Object) - io.temporal.workflow.NexgenRuntime.decodeSequence( - proto.getInput(), converter, Object.class, Object.class)); + proto.getWorkflowType())); + if (proto.hasInput()) builder.setArgs(proto.getInput()); builder.setId(proto.getWorkflowId()); builder.setTaskQueue( io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto( - converter, proto.getTaskQueue())); + proto.getTaskQueue())); builder.setSignal(proto.getSignalName()); - if (proto.hasSignalInput()) - builder.setSignalArgs( - (java.util.List) - (Object) - io.temporal.workflow.NexgenRuntime.decodeSequence( - proto.getSignalInput(), converter, Object.class, Object.class)); + if (proto.hasSignalInput()) builder.setSignalArgs(proto.getSignalInput()); if (proto.hasWorkflowExecutionTimeout()) builder.setExecutionTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, proto.getWorkflowExecutionTimeout())); + proto.getWorkflowExecutionTimeout())); if (proto.hasWorkflowRunTimeout()) builder.setRunTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, proto.getWorkflowRunTimeout())); + proto.getWorkflowRunTimeout())); if (proto.hasWorkflowTaskTimeout()) builder.setTaskTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, proto.getWorkflowTaskTimeout())); + proto.getWorkflowTaskTimeout())); builder.setIdReusePolicy( io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( (proto.getWorkflowIdReusePolicy()).getNumber())); @@ -569,37 +540,26 @@ public static SignalWithStartWorkflowRequest fromProto( if (proto.hasRetryPolicy()) builder.setRetryPolicy( io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyFromProto( - converter, proto.getRetryPolicy())); + proto.getRetryPolicy())); builder.setCronSchedule(proto.getCronSchedule()); - if (proto.hasMemo()) - builder.setMemo( - io.temporal.internal.nexus.system.TemporalModelConverters.memoFromProto( - converter, proto.getMemo())); - if (proto.hasSearchAttributes()) - builder.setSearchAttributes( - io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesFromProto( - converter, proto.getSearchAttributes())); + if (proto.hasMemo()) builder.setMemo(proto.getMemo()); + if (proto.hasSearchAttributes()) builder.setSearchAttributes(proto.getSearchAttributes()); if (proto.hasPriority()) builder.setPriority( io.temporal.internal.nexus.system.TemporalModelConverters.priorityFromProto( - converter, proto.getPriority())); + proto.getPriority())); if (proto.hasVersioningOverride()) builder.setVersioningOverride( io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideFromProto( - converter, proto.getVersioningOverride())); + proto.getVersioningOverride())); if (proto.hasWorkflowStartDelay()) builder.setStartDelay( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - converter, proto.getWorkflowStartDelay())); + proto.getWorkflowStartDelay())); if (proto.hasUserMetadata()) - builder.setUserMetadata( - io.temporal.workflow.UserMetadata.fromProto( - proto.getUserMetadata(), converter, io.temporal.workflow.UserMetadata.class)); + builder.setUserMetadata(io.temporal.workflow.UserMetadata.fromProto(proto.getUserMetadata())); builder.setNamespace(proto.getNamespace()); - if (proto.hasHeader()) - builder.setHeaders( - io.temporal.internal.nexus.system.TemporalModelConverters.headerFromProto( - converter, proto.getHeader())); + if (proto.hasHeader()) builder.setHeaders(proto.getHeader()); return builder.build(); } @@ -611,10 +571,7 @@ public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) } public Object toTransferType(SignalWithStartWorkflowRequest value) { - return value == null - ? null - : value.toProto( - io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); + return value == null ? null : value.toProto(); } public SignalWithStartWorkflowRequest fromTransferType( @@ -622,9 +579,7 @@ public SignalWithStartWorkflowRequest fromTransferType( return value == null ? null : fromProto( - (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value, - io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), - valueType); + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value); } } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java index a433bec3b8..7b21db85fe 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java @@ -68,8 +68,7 @@ public SignalWithStartWorkflowResponse build() { } } - public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto( - io.temporal.common.converter.DataConverter converter) { + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto() { io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); if (this.runId != null) proto.setRunId((this.runId)); @@ -78,9 +77,7 @@ public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRespon } public static SignalWithStartWorkflowResponse fromProto( - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto, - io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type modelType) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto) { Builder builder = SignalWithStartWorkflowResponse.newBuilder(); builder.setRunId(proto.getRunId()); builder.setStarted(proto.getStarted()); @@ -95,10 +92,7 @@ public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) } public Object toTransferType(SignalWithStartWorkflowResponse value) { - return value == null - ? null - : value.toProto( - io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); + return value == null ? null : value.toProto(); } public SignalWithStartWorkflowResponse fromTransferType( @@ -106,9 +100,7 @@ public SignalWithStartWorkflowResponse fromTransferType( return value == null ? null : fromProto( - (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value, - io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), - valueType); + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value); } } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java index 5f46870136..ebb3f47c30 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java @@ -9,28 +9,30 @@ public final class UserMetadata { * Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be * in single-line Temporal Markdown format. */ - private final Object staticSummary; + private final io.temporal.api.common.v1.Payload staticSummary; /** * General fixed details for the workflow execution that may appear in UI and CLI. This can be in * Temporal Markdown format and can span multiple lines. This value is fixed on the workflow * execution and cannot be updated. */ - private final Object staticDetails; + private final io.temporal.api.common.v1.Payload staticDetails; @com.fasterxml.jackson.annotation.JsonCreator public UserMetadata( - @com.fasterxml.jackson.annotation.JsonProperty("staticSummary") Object staticSummary, - @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") Object staticDetails) { + @com.fasterxml.jackson.annotation.JsonProperty("staticSummary") + io.temporal.api.common.v1.Payload staticSummary, + @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") + io.temporal.api.common.v1.Payload staticDetails) { this.staticSummary = staticSummary; this.staticDetails = staticDetails; } - public Object getStaticSummary() { + public io.temporal.api.common.v1.Payload getStaticSummary() { return staticSummary; } - public Object getStaticDetails() { + public io.temporal.api.common.v1.Payload getStaticDetails() { return staticDetails; } @@ -55,16 +57,16 @@ private Builder(UserMetadata value) { this.staticDetails = value.staticDetails; } - private Object staticSummary = null; + private io.temporal.api.common.v1.Payload staticSummary = null; - public Builder setStaticSummary(Object value) { + public Builder setStaticSummary(io.temporal.api.common.v1.Payload value) { this.staticSummary = value; return this; } - private Object staticDetails = null; + private io.temporal.api.common.v1.Payload staticDetails = null; - public Builder setStaticDetails(Object value) { + public Builder setStaticDetails(io.temporal.api.common.v1.Payload value) { this.staticDetails = value; return this; } @@ -74,28 +76,18 @@ public UserMetadata build() { } } - public io.temporal.api.sdk.v1.UserMetadata toProto( - io.temporal.common.converter.DataConverter converter) { + public io.temporal.api.sdk.v1.UserMetadata toProto() { io.temporal.api.sdk.v1.UserMetadata.Builder proto = io.temporal.api.sdk.v1.UserMetadata.newBuilder(); - if (this.staticSummary != null) - proto.setSummary(converter.toPayload((this.staticSummary)).get()); - if (this.staticDetails != null) - proto.setDetails(converter.toPayload((this.staticDetails)).get()); + if (this.staticSummary != null) proto.setSummary((this.staticSummary)); + if (this.staticDetails != null) proto.setDetails((this.staticDetails)); return proto.build(); } - public static UserMetadata fromProto( - io.temporal.api.sdk.v1.UserMetadata proto, - io.temporal.common.converter.DataConverter converter, - java.lang.reflect.Type modelType) { + public static UserMetadata fromProto(io.temporal.api.sdk.v1.UserMetadata proto) { Builder builder = UserMetadata.newBuilder(); - if (proto.hasSummary()) - builder.setStaticSummary( - (Object) converter.fromPayload(proto.getSummary(), Object.class, Object.class)); - if (proto.hasDetails()) - builder.setStaticDetails( - (Object) converter.fromPayload(proto.getDetails(), Object.class, Object.class)); + if (proto.hasSummary()) builder.setStaticSummary(proto.getSummary()); + if (proto.hasDetails()) builder.setStaticDetails(proto.getDetails()); return builder.build(); } @@ -106,19 +98,11 @@ public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) } public Object toTransferType(UserMetadata value) { - return value == null - ? null - : value.toProto( - io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); + return value == null ? null : value.toProto(); } public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueType) { - return value == null - ? null - : fromProto( - (io.temporal.api.sdk.v1.UserMetadata) value, - io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), - valueType); + return value == null ? null : fromProto((io.temporal.api.sdk.v1.UserMetadata) value); } } } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java index 7a420b642b..93da7d2dda 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java @@ -10,36 +10,14 @@ import io.temporal.internal.common.converter.TemporalTransferTypeDataConverter; import io.temporal.internal.payload.visitor.SystemNexusPayloads; import java.lang.reflect.Type; -import java.util.Objects; import java.util.Optional; -import java.util.function.Supplier; import javax.annotation.Nonnull; /** Keeps the server-readable envelope separate from the destination workflow's user converter. */ public final class SystemNexusDataConverter implements DataConverter { public static final String ENDPOINT = "__temporal_system"; - private static final ThreadLocal USER_CONVERTER = new ThreadLocal<>(); private final DataConverter userConverter; - static DataConverter currentDataConverter() { - DataConverter converter = USER_CONVERTER.get(); - if (converter == null) - throw new IllegalStateException("System Nexus user converter context is not active"); - return converter; - } - - static T withDataConverter(DataConverter converter, Supplier action) { - Objects.requireNonNull(converter, "converter"); - DataConverter previous = USER_CONVERTER.get(); - USER_CONVERTER.set(converter); - try { - return action.get(); - } finally { - if (previous == null) USER_CONVERTER.remove(); - else USER_CONVERTER.set(previous); - } - } - public SystemNexusDataConverter(DataConverter userConverter) { this.userConverter = userConverter; } @@ -47,33 +25,23 @@ public SystemNexusDataConverter(DataConverter userConverter) { @Override public Optional toPayload(T value) { if (value instanceof RawValue) return Optional.of(((RawValue) value).getPayload()); - return withDataConverter( - userConverter, - () -> { - Object transferred = TemporalTransferTypeDataConverter.toTransferValue(value); - if (!(transferred instanceof Message)) - throw new DataConverterException( - "System Nexus inputs must have a protobuf transfer type"); - return Optional.of(SystemNexusPayloads.pack((Message) transferred)); - }); + Object transferred = TemporalTransferTypeDataConverter.toTransferValue(value); + if (!(transferred instanceof Message)) + throw new DataConverterException("System Nexus inputs must have a protobuf transfer type"); + return Optional.of(SystemNexusPayloads.pack((Message) transferred)); } @Override public T fromPayload(Payload payload, Class valueClass, Type valueType) { if (valueClass == RawValue.class) return valueClass.cast(new RawValue(payload)); - return withDataConverter( - userConverter, - () -> { - Message value = SystemNexusPayloads.unpack(payload).build(); - TemporalTransferTypeDataConverter.TransferType transfer = - TemporalTransferTypeDataConverter.transferTypeFor(valueClass, valueType); - if (transfer == null) return valueClass.cast(value); - if (!transfer.getRawType().isInstance(value)) - throw new DataConverterException( - "Unexpected system Nexus response type: " - + value.getDescriptorForType().getFullName()); - return transfer.fromValue(value, valueClass); - }); + Message value = SystemNexusPayloads.unpack(payload).build(); + TemporalTransferTypeDataConverter.TransferType transfer = + TemporalTransferTypeDataConverter.transferTypeFor(valueClass, valueType); + if (transfer == null) return valueClass.cast(value); + if (!transfer.getRawType().isInstance(value)) + throw new DataConverterException( + "Unexpected system Nexus response type: " + value.getDescriptorForType().getFullName()); + return transfer.fromValue(value, valueClass); } @Override diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java index 57825ebcef..1ab902c1f9 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -1,27 +1,23 @@ package io.temporal.internal.nexus.system; -import io.temporal.api.common.v1.*; +import io.temporal.api.common.v1.Priority; +import io.temporal.api.common.v1.RetryPolicy; +import io.temporal.api.common.v1.WorkflowType; import io.temporal.api.taskqueue.v1.TaskQueue; import io.temporal.common.RetryOptions; import io.temporal.common.VersioningOverride; -import io.temporal.common.converter.DataConverter; -import io.temporal.internal.common.*; +import io.temporal.internal.common.ProtoConverters; +import io.temporal.internal.common.ProtobufTimeUtils; +import io.temporal.internal.common.RetryOptionsUtils; import io.temporal.payload.context.WorkflowSerializationContext; import io.temporal.workflow.SignalWithStartWorkflowRequest; import io.temporal.workflow.Workflow; import java.time.Duration; -import java.util.LinkedHashMap; -import java.util.Map; -/** SDK-owned model conversion hooks used by the generated system Nexus bindings. */ +/** SDK-owned structural conversion hooks used by the generated system Nexus bindings. */ public final class TemporalModelConverters { private TemporalModelConverters() {} - /** Returns the user converter active during system Nexus transfer conversion. */ - public static DataConverter currentDataConverter() { - return SystemNexusDataConverter.currentDataConverter(); - } - public static String workflowNamespace() { return Workflow.getInfo().getNamespace(); } @@ -31,121 +27,54 @@ public static WorkflowSerializationContext signalWithStartWorkflowSerializationC return new WorkflowSerializationContext(request.getNamespace(), request.getId()); } - public static RuntimeException failureFromProto( - DataConverter converter, io.temporal.api.failure.v1.Failure value) { - return converter.failureToException(value); - } - - public static io.temporal.api.failure.v1.Failure failureToProto( - DataConverter converter, RuntimeException value) { - return converter.exceptionToFailure(value); - } - - public static WorkflowType workflowTypeToProto(DataConverter converter, String value) { + public static WorkflowType workflowTypeToProto(String value) { return WorkflowType.newBuilder().setName(value).build(); } - public static String workflowTypeFromProto(DataConverter converter, WorkflowType value) { + public static String workflowTypeFromProto(WorkflowType value) { return value.getName(); } - public static TaskQueue taskQueueToProto(DataConverter converter, String value) { + public static TaskQueue taskQueueToProto(String value) { return TaskQueue.newBuilder().setName(value).build(); } - public static String taskQueueFromProto(DataConverter converter, TaskQueue value) { + public static String taskQueueFromProto(TaskQueue value) { return value.getName(); } - public static com.google.protobuf.Duration durationToProto( - DataConverter converter, Duration value) { + public static com.google.protobuf.Duration durationToProto(Duration value) { return ProtobufTimeUtils.toProtoDuration(value); } - public static Duration durationFromProto( - DataConverter converter, com.google.protobuf.Duration value) { + public static Duration durationFromProto(com.google.protobuf.Duration value) { return ProtobufTimeUtils.toJavaDuration(value); } - public static RetryPolicy retryPolicyToProto(DataConverter converter, RetryOptions value) { + public static RetryPolicy retryPolicyToProto(RetryOptions value) { return RetryOptionsUtils.toRetryPolicy(value).build(); } - public static RetryOptions retryPolicyFromProto(DataConverter converter, RetryPolicy value) { + public static RetryOptions retryPolicyFromProto(RetryPolicy value) { return RetryOptionsUtils.toRetryOptions(value); } - public static Memo memoToProto(DataConverter converter, Map value) { - Memo.Builder builder = Memo.newBuilder(); - value.forEach((key, item) -> builder.putFields(key, converter.toPayload(item).get())); - return builder.build(); - } - - public static Map memoFromProto(DataConverter converter, Memo value) { - Map result = new LinkedHashMap<>(); - value - .getFieldsMap() - .forEach( - (key, payload) -> - result.put(key, converter.fromPayload(payload, Object.class, Object.class))); - return result; - } - - public static Header headerToProto(DataConverter converter, Map value) { - Header.Builder builder = Header.newBuilder(); - value.forEach( - (key, payload) -> - builder.putFields( - key, - converter.toPayload(new io.temporal.common.converter.RawValue(payload)).get())); - return builder.build(); - } - - public static Map headerFromProto(DataConverter converter, Header value) { - Map result = new LinkedHashMap<>(); - value - .getFieldsMap() - .forEach( - (key, payload) -> - result.put( - key, - converter - .fromPayload( - payload, - io.temporal.common.converter.RawValue.class, - io.temporal.common.converter.RawValue.class) - .getPayload())); - return result; - } - - public static io.temporal.api.common.v1.SearchAttributes searchAttributesToProto( - DataConverter converter, io.temporal.common.SearchAttributes value) { - return SearchAttributesUtil.encodeTyped(value); - } - - public static io.temporal.common.SearchAttributes searchAttributesFromProto( - DataConverter converter, io.temporal.api.common.v1.SearchAttributes value) { - return SearchAttributesUtil.decodeTyped(value); - } - - public static Priority priorityToProto( - DataConverter converter, io.temporal.common.Priority value) { + public static Priority priorityToProto(io.temporal.common.Priority value) { return ProtoConverters.toProto(value); } - public static io.temporal.common.Priority priorityFromProto( - DataConverter converter, Priority value) { + public static io.temporal.common.Priority priorityFromProto(Priority value) { return ProtoConverters.fromProto(value); } public static io.temporal.api.workflow.v1.VersioningOverride versioningOverrideToProto( - DataConverter converter, VersioningOverride value) { + VersioningOverride value) { return ProtoConverters.toProto(value); } @SuppressWarnings("deprecation") public static VersioningOverride versioningOverrideFromProto( - DataConverter converter, io.temporal.api.workflow.v1.VersioningOverride value) { + io.temporal.api.workflow.v1.VersioningOverride value) { if (value.hasOneTime()) return new VersioningOverride.OneTimeVersioningOverride( deployment(value.getOneTime().getTargetDeploymentVersion())); diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index 79855f808f..e6188cce61 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -31,16 +31,17 @@ to match the SDK's Spotless configuration. Nex-gen downloads and caches its standalone JAR on first use; for offline regeneration, set `NEXGEN_JAVA_FORMAT_JAR` to a local all-dependencies JAR. A JDK must be on `PATH`. -`TemporalModelConverters` contains the SDK-owned conversion helpers. The emitted -`NexgenRuntime` contains only payload-sequence decoding. Converter scoping lives -in `SystemNexusDataConverter`; generated transfer converters obtain the active -converter through `TemporalModelConverters.currentDataConverter()` and fail -when no scope is active, matching Python. Protobuf field access is generated -directly. Nex-gen assembles the required runtime helpers from Rust strings. +`TemporalModelConverters` contains SDK-owned structural conversion helpers. +Generated models preserve embedded payloads, batches, memo, headers, search +attributes, and failure details in serialized form. Transfer conversion copies +them without invoking a user converter or needing type hints. These bindings +require no `NexgenRuntime` or converter scope. API code serializes user values +when constructing a request and supplies expected types when decoding results. Normal Java SDK builds do not require Rust or nex-gen. The SDK wraps any configured `DataConverter` in `SystemNexusDataConverter` for -system operations. That wrapper handles the outer envelope and delegates nested -user conversion; custom converters do not need to recognize system envelopes. +system operations. That wrapper handles the outer envelope; embedded values are +already serialized. It delegates operation failure conversion to the configured +converter. Custom converters do not need to recognize system envelopes. The shared payload visitor descends into marked envelopes for payload traversal. `CodecDataConverter` contains no system Nexus handling. diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md index 068a9d73ce..aa45582e56 100644 --- a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -1,34 +1,46 @@ # Signal with start inside workflows -The generated workflow API atomically signals an external workflow, starting it -when necessary. It requires a server supporting the system workflow service. +The generated workflow operation atomically signals an external workflow, +starting it when necessary. It requires a server supporting the system workflow +service. Its request model is a low-level serialized representation; an ergonomic +API with required parameters and options containing user values is future work. + +Request construction must serialize user values with the configured converter +and destination workflow context. Given that converter as `configuredConverter`: ```java +String namespace = Workflow.getInfo().getNamespace(); +String workflowId = "target"; +DataConverter converter = configuredConverter.withContext( + new WorkflowSerializationContext(namespace, workflowId)); ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( SignalWithStartWorkflowRequest.newBuilder() .setWorkflow("TargetWorkflow") .setSignal("notify") - .setId("target") + .setId(workflowId) + .setNamespace(namespace) .setTaskQueue("target-queue") - .setArgs(Collections.singletonList(input)) - .setSignalArgs(Collections.singletonList(signal)) + .setArgs(converter.toPayloads(input).get()) + .setSignalArgs(converter.toPayloads(signal).get()) .build()); ``` Import `Workflow`, `SignalWithStartWorkflowRequest`, and `ExternalWorkflowStub` -from `io.temporal.workflow`. The generated request builder contains the API's -options, including timeouts, retry policy, memo, conflict policy, and flattened -static summary/details setters. Workflow ID and task queue are explicit request -fields. Namespace defaults to the caller's namespace. Request ID is omitted: -the system service manages it. +from `io.temporal.workflow`, `DataConverter` from +`io.temporal.common.converter`, and `WorkflowSerializationContext` from +`io.temporal.payload.context`. Payload-bearing fields, including memo, headers, +static summary/details, and search attributes, retain serialized protobuf values. +The generated builder also carries timeouts, retry policy, and conflict policy. +Namespace defaults to the caller's namespace. Request ID is omitted: the system +service manages it. The call returns after signal delivery/start completes. The returned external stub supports further signals and cancellation. Use `Async.function(Workflow::signalWithStartWorkflow, request)` for a promise. `Workflow` inherits generated operations from `WorkflowOperations`. New WIT -operations become available after regeneration, without adding handwritten -options, capture proxies, stubs, or facade methods. The output transform, request -fields, and serialization-context hook are declared in WIT. The converter uses -the destination namespace and workflow ID for nested payloads, codecs, and -failures; the outer system envelope remains server-readable. +operations become available after regeneration. The output transform, request +fields, and serialization-context hook are declared in WIT. Transfer conversion +preserves serialized payloads and whole batches without decoding them. Future +typed APIs can decode embedded results with their expected types. The outer +system envelope remains server-readable. diff --git a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit index 5a61e9de2d..b0d117a6c2 100644 --- a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit +++ b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit @@ -6,7 +6,7 @@ interface model { /// @nexus.proto "temporal.api.common.v1.Payload" typescript-import="@temporalio/proto" /// @nexus.type - /// java="Object" + /// java="io.temporal.api.common.v1.Payload" /// python="typing.Any" /// typescript="common.Payload" /// go="any" @@ -19,20 +19,18 @@ interface model { /// @nexus.proto "temporal.api.common.v1.Payloads" /// typescript-import="@temporalio/proto" /// @nexus.type - /// java="java.util.List" + /// java="io.temporal.api.common.v1.Payloads" /// go="[]any" /// dotnet="IReadOnlyCollection" /// dotnet-from="ProtoExtensions.FromPayloads" /// dotnet-to="ProtoExtensions.ToPayloads" type payloads = list; - /// Temporal failure represented by the target SDK's native exception/error type. - /// The SDK failure converter owns the recursive cause and failure-info structure. + /// Temporal failure represented by a serialized protobuf or SDK-native error. + /// The surrounding SDK API owns payload serialization and typed decoding. /// @nexus.proto "temporal.api.failure.v1.Failure" typescript-import="@temporalio/proto" /// @nexus.type - /// java="RuntimeException" - /// java-from="failureFromProto" - /// java-to="failureToProto" + /// java="io.temporal.api.failure.v1.Failure" /// python="BaseException" /// typescript="Error" /// go="error" @@ -138,9 +136,7 @@ interface model { /// @nexus.proto "temporal.api.common.v1.Memo" typescript-import="@temporalio/proto" /// @nexus.type - /// java="java.util.Map" - /// java-from="memoFromProto" - /// java-to="memoToProto" + /// java="io.temporal.api.common.v1.Memo" /// python="collections.abc.Mapping[str, typing.Any]" /// typescript="Record" /// go="map[string]any" @@ -150,9 +146,7 @@ interface model { /// @nexus.proto "temporal.api.common.v1.Header" typescript-import="@temporalio/proto" /// @nexus.type - /// java="java.util.Map" - /// java-from="headerFromProto" - /// java-to="headerToProto" + /// java="io.temporal.api.common.v1.Header" /// python="collections.abc.Mapping[str, typing.Any]" /// typescript="common.Headers" /// go="map[string]any" @@ -164,9 +158,7 @@ interface model { /// @nexus.proto "temporal.api.common.v1.SearchAttributes" typescript-import="@temporalio/proto" /// @nexus.type - /// java="io.temporal.common.SearchAttributes" - /// java-from="searchAttributesFromProto" - /// java-to="searchAttributesToProto" + /// java="io.temporal.api.common.v1.SearchAttributes" /// python="temporalio.common.TypedSearchAttributes" /// typescript="common.TypedSearchAttributes" /// go="go.temporal.io/sdk/temporal.SearchAttributes" diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java index 04fedd2700..f44a8551bd 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java @@ -1,11 +1,13 @@ package io.temporal.internal.nexus.system; import static org.junit.Assert.*; -import static org.mockito.AdditionalAnswers.delegatesTo; import static org.mockito.Mockito.*; import com.google.protobuf.ByteString; +import io.temporal.api.common.v1.Header; +import io.temporal.api.common.v1.Memo; import io.temporal.api.common.v1.Payload; +import io.temporal.api.common.v1.Payloads; import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest; import io.temporal.common.converter.*; import io.temporal.internal.payload.visitor.SystemNexusPayloads; @@ -23,19 +25,38 @@ public class SystemNexusDataConverterTest { private static final String OPERATION = "SignalWithStartWorkflowExecution"; private static SignalWithStartWorkflowRequest request(String id) { + return request(id, DefaultDataConverter.STANDARD_INSTANCE); + } + + private static SignalWithStartWorkflowRequest request(String id, DataConverter converter) { return SignalWithStartWorkflowRequest.newBuilder() .setNamespace("destination") .setId(id) .setWorkflow("Target") .setTaskQueue("queue") .setSignal("notify") - .setArgs(Arrays.asList("workflow", 42)) - .setSignalArgs(Collections.singletonList("signal")) - .setMemo(Collections.singletonMap("memo", "value")) + .setArgs(converter.toPayloads("workflow", 42).get()) + .setSignalArgs(converter.toPayloads("signal").get()) + .setMemo(Memo.newBuilder().putFields("memo", converter.toPayload("value").get()).build()) .setHeaders( - Collections.singletonMap( - "trace", DefaultDataConverter.STANDARD_INSTANCE.toPayload("trace-value").get())) - .setUserMetadata(UserMetadata.newBuilder().setStaticSummary("summary").build()) + Header.newBuilder() + .putFields("trace", converter.toPayload("trace-value").get()) + .build()) + .setUserMetadata( + UserMetadata.newBuilder() + .setStaticSummary(converter.toPayload("summary").get()) + .setStaticDetails(converter.toPayload("details").get()) + .build()) + .setSearchAttributes( + io.temporal.api.common.v1.SearchAttributes.newBuilder() + .putIndexedFields( + "key", + Payload.newBuilder() + .putMetadata( + "encoding", ByteString.copyFromUtf8("unknown/search-attribute")) + .setData(ByteString.copyFromUtf8("opaque")) + .build()) + .build()) .build(); } @@ -64,17 +85,19 @@ public void decodesUnmarkedServerResponse() { @Test public void nestedPayloadsUseDestinationContextAndOuterEnvelopeBypassesCodecs() throws Exception { - SignalWithStartWorkflowRequest request = request("target"); WorkflowSerializationContext context = - (WorkflowSerializationContext) - SystemNexusOperations.serializationContext(SERVICE, OPERATION, request); - assertEquals("destination", context.getNamespace()); - assertEquals("target", context.getWorkflowId()); + new WorkflowSerializationContext("destination", "target"); DataConverter user = new CodecDataConverter( DefaultDataConverter.STANDARD_INSTANCE, Collections.singletonList(new ContextCodec(null))) .withContext(context); + SignalWithStartWorkflowRequest request = request("target", user); + WorkflowSerializationContext acquired = + (WorkflowSerializationContext) + SystemNexusOperations.serializationContext(SERVICE, OPERATION, request); + assertEquals("destination", acquired.getNamespace()); + assertEquals("target", acquired.getWorkflowId()); SystemNexusDataConverter converter = new SystemNexusDataConverter(user); Payload encoded = converter.toPayload(request).get(); assertTrue(SystemNexusPayloads.isSystemPayload(encoded)); @@ -97,32 +120,30 @@ public void nestedPayloadsUseDestinationContextAndOuterEnvelopeBypassesCodecs() assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); assertEquals(request.getMemo(), decoded.getMemo()); assertEquals(request.getHeaders(), decoded.getHeaders()); + assertEquals(request.getSearchAttributes(), decoded.getSearchAttributes()); + assertEquals( + request.getUserMetadata().getStaticDetails(), decoded.getUserMetadata().getStaticDetails()); assertEquals( "target", wire.getHeader() .getFieldsOrThrow("trace") .getMetadataOrThrow("test-context") .toStringUtf8()); - assertEquals("summary", decoded.getUserMetadata().getStaticSummary()); + assertEquals( + "summary", + user.fromPayload(decoded.getUserMetadata().getStaticSummary(), String.class, String.class)); } @Test - public void customDataConverterReceivesUserValuesWithoutSystemEnvelopeHandling() - throws Exception { + public void transferConversionDoesNotUseTheUserConverter() throws Exception { SignalWithStartWorkflowRequest request = request("target"); - DataConverter user = - mock(DataConverter.class, delegatesTo(DefaultDataConverter.STANDARD_INSTANCE)); + DataConverter user = mock(DataConverter.class); SystemNexusDataConverter converter = new SystemNexusDataConverter(user); Payload encoded = converter.toPayload(request).get(); assertTrue(SystemNexusPayloads.isSystemPayload(encoded)); SignalWithStartWorkflowExecutionRequest wire = SignalWithStartWorkflowExecutionRequest.parseFrom(encoded.getData()); assertEquals("target", wire.getWorkflowId()); - verify(user).toPayloads("workflow", 42); - verify(user).toPayloads("signal"); - verify(user).toPayload("value"); - verify(user, never()).toPayload(request); - verify(user, never()).toPayload(isA(com.google.protobuf.Message.class)); SignalWithStartWorkflowRequest decoded = converter.fromPayload( encoded, SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class); @@ -130,10 +151,11 @@ public void customDataConverterReceivesUserValuesWithoutSystemEnvelopeHandling() assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); assertEquals(request.getMemo(), decoded.getMemo()); assertEquals(request.getHeaders(), decoded.getHeaders()); + verifyNoInteractions(user); } @Test - public void responseAndRawValuesRoundTripAndConverterScopesRestore() { + public void responseAndRawValuesRoundTrip() { SystemNexusDataConverter converter = new SystemNexusDataConverter(DefaultDataConverter.STANDARD_INSTANCE); SignalWithStartWorkflowResponse response = @@ -148,57 +170,32 @@ public void responseAndRawValuesRoundTripAndConverterScopesRestore() { SignalWithStartWorkflowResponse.class) .getRunId()); assertSame(encoded, converter.toPayload(new RawValue(encoded)).get()); - assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); } @Test - public void converterScopesRestoreAfterNestedFailure() { - DataConverter outer = DefaultDataConverter.STANDARD_INSTANCE; - DataConverter inner = new DefaultDataConverter(); - assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); - SystemNexusDataConverter.withDataConverter( - outer, - () -> { - assertSame(outer, TemporalModelConverters.currentDataConverter()); - assertThrows( - IllegalArgumentException.class, - () -> - SystemNexusDataConverter.withDataConverter( - inner, - () -> { - assertSame(inner, TemporalModelConverters.currentDataConverter()); - throw new IllegalArgumentException("test"); - })); - assertSame(outer, TemporalModelConverters.currentDataConverter()); - return null; - }); - assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); - } - - @Test - public void transferConversionRequiresActiveUserConverter() { + public void transferConversionRequiresNoConverterContextOrTypeHints() { SignalWithStartWorkflowRequest.Converter converter = new SignalWithStartWorkflowRequest.Converter(); - IllegalStateException encodeFailure = - assertThrows( - IllegalStateException.class, () -> converter.toTransferType(request("target"))); - assertEquals("System Nexus user converter context is not active", encodeFailure.getMessage()); - assertThrows( - IllegalStateException.class, - () -> - converter.fromTransferType( - SignalWithStartWorkflowExecutionRequest.getDefaultInstance(), - SignalWithStartWorkflowRequest.class)); + SignalWithStartWorkflowRequest request = request("target"); + SignalWithStartWorkflowRequest decoded = + converter.fromTransferType( + converter.toTransferType(request), SignalWithStartWorkflowRequest.class); + assertEquals(request.getArgs(), decoded.getArgs()); + assertEquals(request.getMemo(), decoded.getMemo()); } @Test - public void operationsRetainIndependentDestinationConverters() { - SignalWithStartWorkflowRequest first = request("first"); - SignalWithStartWorkflowRequest second = request("second"); + public void requestsRetainIndependentlySerializedDestinationPayloads() { DataConverter base = new CodecDataConverter( DefaultDataConverter.STANDARD_INSTANCE, Collections.singletonList(new ContextCodec(null))); + SignalWithStartWorkflowRequest first = + request( + "first", base.withContext(new WorkflowSerializationContext("destination", "first"))); + SignalWithStartWorkflowRequest second = + request( + "second", base.withContext(new WorkflowSerializationContext("destination", "second"))); SystemNexusDataConverter firstConverter = new SystemNexusDataConverter( base.withContext( @@ -209,6 +206,11 @@ public void operationsRetainIndependentDestinationConverters() { SystemNexusOperations.serializationContext(SERVICE, OPERATION, second))); Payload firstPayload = firstConverter.toPayload(first).get(); Payload secondPayload = secondConverter.toPayload(second).get(); + assertEquals( + "first", first.getArgs().getPayloads(0).getMetadataOrThrow("test-context").toStringUtf8()); + assertEquals( + "second", + second.getArgs().getPayloads(0).getMetadataOrThrow("test-context").toStringUtf8()); assertEquals( "second", secondConverter @@ -225,7 +227,58 @@ public void operationsRetainIndependentDestinationConverters() { SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class) .getId()); - assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + } + + @Test + public void packedSequencesStayOpaqueUntilTheCallerDecodesWithKnownTypes() { + DataConverter user = + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, Collections.singletonList(new PackingCodec())); + SignalWithStartWorkflowRequest request = request("target", user); + assertEquals(1, request.getArgs().getPayloadsCount()); + SystemNexusDataConverter converter = new SystemNexusDataConverter(mock(DataConverter.class)); + Payload envelope = converter.toPayload(request).get(); + SignalWithStartWorkflowRequest decoded = + converter.fromPayload( + envelope, SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class); + assertEquals(request.getArgs(), decoded.getArgs()); + assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); + assertEquals(request.getMemo(), decoded.getMemo()); + assertEquals( + request.getUserMetadata().getStaticSummary(), decoded.getUserMetadata().getStaticSummary()); + assertArrayEquals( + new Object[] {"workflow", 42}, + user.fromPayloads( + Optional.of(decoded.getArgs()), + new Class[] {String.class, Integer.class}, + new java.lang.reflect.Type[] {String.class, Integer.class})); + } + + private static final class PackingCodec implements PayloadCodec { + @Nonnull + @Override + public List encode(@Nonnull List values) { + return Collections.singletonList( + Payload.newBuilder() + .putMetadata("encoding", ByteString.copyFromUtf8("test/packed")) + .setData(Payloads.newBuilder().addAllPayloads(values).build().toByteString()) + .build()); + } + + @Nonnull + @Override + public List decode(@Nonnull List values) { + List decoded = new ArrayList<>(); + for (Payload value : values) { + assertEquals("test/packed", value.getMetadataOrThrow("encoding").toStringUtf8()); + try { + decoded.addAll(Payloads.parseFrom(value.getData()).getPayloadsList()); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw new AssertionError(e); + } + } + return decoded; + } } @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java index d03bb45a9c..fd37a4f005 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.*; +import io.temporal.common.converter.DefaultDataConverter; import io.temporal.common.interceptors.*; import io.temporal.testing.internal.SDKTestWorkflowRule; import io.temporal.worker.WorkerFactoryOptions; @@ -43,8 +44,20 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { request.getNamespace()); assertEquals("notify", request.getSignal()); assertEquals("queue", request.getTaskQueue()); - assertEquals("input", request.getArgs().get(0)); - assertEquals("signal", request.getSignalArgs().get(0)); + assertEquals( + "input", + DefaultDataConverter.STANDARD_INSTANCE.fromPayloads( + 0, + java.util.Optional.of(request.getArgs()), + String.class, + String.class)); + assertEquals( + "signal", + DefaultDataConverter.STANDARD_INSTANCE.fromPayloads( + 0, + java.util.Optional.of(request.getSignalArgs()), + String.class, + String.class)); return new ExecuteNexusOperationOutput<>( Workflow.newPromise( SignalWithStartWorkflowResponse.newBuilder() @@ -80,8 +93,8 @@ public String run() { .setSignal("notify") .setId("sync") .setTaskQueue("queue") - .setArgs(java.util.Collections.singletonList("input")) - .setSignalArgs(java.util.Collections.singletonList("signal")) + .setArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("input").get()) + .setSignalArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("signal").get()) .build(); ExternalWorkflowStub sync = Workflow.signalWithStartWorkflow(request); ExternalWorkflowStub async = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java index ec54c2e571..1d78c9b9b2 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; +import io.temporal.common.converter.DefaultDataConverter; import io.temporal.testing.CloudTestExclusion.RequiresCloudProvisioning; import io.temporal.testing.CloudTestExclusionNote; import io.temporal.testing.WorkflowReplayer; @@ -82,16 +83,16 @@ public String run() { .setTaskQueue(Workflow.getInfo().getTaskQueue()) .setIdConflictPolicy( WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) - .setArgs(java.util.Collections.singletonList("start")) - .setSignalArgs(java.util.Collections.singletonList("first")) + .setArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("start").get()) + .setSignalArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("first").get()) .build(); ExternalWorkflowStub external = Workflow.signalWithStartWorkflow(request); assertEquals(id, external.getExecution().getWorkflowId()); Async.function( Workflow::signalWithStartWorkflow, request.toBuilder() - .setArgs(java.util.Collections.singletonList("ignored")) - .setSignalArgs(java.util.Collections.singletonList("second")) + .setArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("ignored").get()) + .setSignalArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("second").get()) .build()) .get(); return id; From 01033c82ab9ac74ede118f54e26cebdc392dbd00 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Tue, 20 Oct 2026 10:47:42 -0700 Subject: [PATCH 09/17] Revert "Preserve serialized embedded payloads in system Nexus models" This reverts commit dd65bc877d2210f59e9960725bb8987278915bb5. --- CHANGELOG.md | 6 +- .../io/temporal/workflow/NexgenRuntime.java | 19 ++ .../SignalWithStartWorkflowRequest.java | 169 +++++++++++------ .../SignalWithStartWorkflowResponse.java | 16 +- .../io/temporal/workflow/UserMetadata.java | 56 ++++-- .../system/SystemNexusDataConverter.java | 56 ++++-- .../nexus/system/TemporalModelConverters.java | 109 +++++++++-- temporal-sdk/src/main/nexus/README.md | 17 +- .../src/main/nexus/SIGNAL_WITH_START.md | 42 ++-- .../nexus/deps/nexus-temporal-types/model.wit | 24 ++- .../system/SystemNexusDataConverterTest.java | 179 ++++++------------ .../nexus/SignalWithStartWorkflowTest.java | 21 +- .../SystemSignalWithStartIntegrationTest.java | 9 +- 13 files changed, 420 insertions(+), 303 deletions(-) create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 580ac40bd6..f3e5554dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,10 +31,8 @@ to docs, or any other relevant information. - Workflows can signal with start through the system workflow service using generated `Workflow.signalWithStartWorkflow(SignalWithStartWorkflowRequest)` API. Request builders and operations are generated into `io.temporal.workflow`. - Request models carry serialized protobuf payloads; API code serializes user values with the - destination workflow context before constructing the request. Transfer conversion preserves - opaque payload batches, and payload visitation supports external storage inside system envelopes. - Requires a server supporting the system workflow service. + System Nexus envelopes preserve destination workflow serialization context for nested payloads, + codecs, and external payload storage. Requires a server supporting the system workflow service. - Applications can use the experimental `@TransferTypeConvertible` annotation and `TransferTypeConverter` interface to convert top-level model values to transfer types. The SDK applies this conversion to workflow, activity, Nexus, and schedule payloads, including failure diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java new file mode 100644 index 0000000000..7fd49cfaa1 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/NexgenRuntime.java @@ -0,0 +1,19 @@ +// Generated by nexgen. DO NOT EDIT! +package io.temporal.workflow; + +/** Shared conversion helpers used by these generated models. */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class NexgenRuntime { + private NexgenRuntime() {} + + public static java.util.List decodeSequence( + io.temporal.api.common.v1.Payloads payloads, + io.temporal.common.converter.DataConverter converter, + Class elementClass, + java.lang.reflect.Type elementType) { + java.util.List result = new java.util.ArrayList<>(); + for (io.temporal.api.common.v1.Payload payload : payloads.getPayloadsList()) + result.add(converter.fromPayload(payload, elementClass, elementType)); + return result; + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java index 50d898f460..e1bb6ed755 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java @@ -9,7 +9,7 @@ public final class SignalWithStartWorkflowRequest { private final String workflow; /** Arguments for the workflow. */ - private final io.temporal.api.common.v1.Payloads args; + private final java.util.List args; /** Unique identifier for the workflow execution. Must be nonempty. */ private final String id; @@ -20,7 +20,7 @@ public final class SignalWithStartWorkflowRequest { private final String signal; /** Arguments for the signal. */ - private final io.temporal.api.common.v1.Payloads signalArgs; + private final java.util.List signalArgs; /** * Total workflow execution timeout, including retries and continue-as-new. Defaults to unlimited. @@ -50,10 +50,10 @@ public final class SignalWithStartWorkflowRequest { private final String cronSchedule; /** Memo for the workflow. */ - private final io.temporal.api.common.v1.Memo memo; + private final java.util.Map memo; /** Typed search attributes for the workflow. */ - private final io.temporal.api.common.v1.SearchAttributes searchAttributes; + private final io.temporal.common.SearchAttributes searchAttributes; /** Priority of the workflow execution. */ private final io.temporal.common.Priority priority; @@ -71,18 +71,17 @@ public final class SignalWithStartWorkflowRequest { private final String namespace; /** Headers for the request. */ - private final io.temporal.api.common.v1.Header headers; + private final java.util.Map headers; @com.fasterxml.jackson.annotation.JsonCreator public SignalWithStartWorkflowRequest( @com.fasterxml.jackson.annotation.JsonProperty("workflow") String workflow, - @com.fasterxml.jackson.annotation.JsonProperty("args") - io.temporal.api.common.v1.Payloads args, + @com.fasterxml.jackson.annotation.JsonProperty("args") java.util.List args, @com.fasterxml.jackson.annotation.JsonProperty("id") String id, @com.fasterxml.jackson.annotation.JsonProperty("taskQueue") String taskQueue, @com.fasterxml.jackson.annotation.JsonProperty("signal") String signal, @com.fasterxml.jackson.annotation.JsonProperty("signalArgs") - io.temporal.api.common.v1.Payloads signalArgs, + java.util.List signalArgs, @com.fasterxml.jackson.annotation.JsonProperty("executionTimeout") java.time.Duration executionTimeout, @com.fasterxml.jackson.annotation.JsonProperty("runTimeout") java.time.Duration runTimeout, @@ -94,9 +93,9 @@ public SignalWithStartWorkflowRequest( @com.fasterxml.jackson.annotation.JsonProperty("retryPolicy") io.temporal.common.RetryOptions retryPolicy, @com.fasterxml.jackson.annotation.JsonProperty("cronSchedule") String cronSchedule, - @com.fasterxml.jackson.annotation.JsonProperty("memo") io.temporal.api.common.v1.Memo memo, + @com.fasterxml.jackson.annotation.JsonProperty("memo") java.util.Map memo, @com.fasterxml.jackson.annotation.JsonProperty("searchAttributes") - io.temporal.api.common.v1.SearchAttributes searchAttributes, + io.temporal.common.SearchAttributes searchAttributes, @com.fasterxml.jackson.annotation.JsonProperty("priority") io.temporal.common.Priority priority, @com.fasterxml.jackson.annotation.JsonProperty("versioningOverride") @@ -106,7 +105,7 @@ public SignalWithStartWorkflowRequest( io.temporal.workflow.UserMetadata userMetadata, @com.fasterxml.jackson.annotation.JsonProperty("namespace") String namespace, @com.fasterxml.jackson.annotation.JsonProperty("headers") - io.temporal.api.common.v1.Header headers) { + java.util.Map headers) { this.workflow = workflow; this.args = args; this.id = id; @@ -134,7 +133,7 @@ public String getWorkflow() { return workflow; } - public io.temporal.api.common.v1.Payloads getArgs() { + public java.util.List getArgs() { return args; } @@ -150,7 +149,7 @@ public String getSignal() { return signal; } - public io.temporal.api.common.v1.Payloads getSignalArgs() { + public java.util.List getSignalArgs() { return signalArgs; } @@ -182,11 +181,11 @@ public String getCronSchedule() { return cronSchedule; } - public io.temporal.api.common.v1.Memo getMemo() { + public java.util.Map getMemo() { return memo; } - public io.temporal.api.common.v1.SearchAttributes getSearchAttributes() { + public io.temporal.common.SearchAttributes getSearchAttributes() { return searchAttributes; } @@ -210,7 +209,7 @@ public String getNamespace() { return namespace; } - public io.temporal.api.common.v1.Header getHeaders() { + public java.util.Map getHeaders() { return headers; } @@ -261,9 +260,9 @@ public Builder setWorkflow(String value) { return this; } - private io.temporal.api.common.v1.Payloads args = null; + private java.util.List args = null; - public Builder setArgs(io.temporal.api.common.v1.Payloads value) { + public Builder setArgs(java.util.List value) { this.args = value; return this; } @@ -289,9 +288,9 @@ public Builder setSignal(String value) { return this; } - private io.temporal.api.common.v1.Payloads signalArgs = null; + private java.util.List signalArgs = null; - public Builder setSignalArgs(io.temporal.api.common.v1.Payloads value) { + public Builder setSignalArgs(java.util.List value) { this.signalArgs = value; return this; } @@ -346,16 +345,16 @@ public Builder setCronSchedule(String value) { return this; } - private io.temporal.api.common.v1.Memo memo = null; + private java.util.Map memo = null; - public Builder setMemo(io.temporal.api.common.v1.Memo value) { + public Builder setMemo(java.util.Map value) { this.memo = value; return this; } - private io.temporal.api.common.v1.SearchAttributes searchAttributes = null; + private io.temporal.common.SearchAttributes searchAttributes = null; - public Builder setSearchAttributes(io.temporal.api.common.v1.SearchAttributes value) { + public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { this.searchAttributes = value; return this; } @@ -395,14 +394,14 @@ public Builder setNamespace(String value) { return this; } - private io.temporal.api.common.v1.Header headers = null; + private java.util.Map headers = null; - public Builder setHeaders(io.temporal.api.common.v1.Header value) { + public Builder setHeaders(java.util.Map value) { this.headers = value; return this; } - public Builder setStaticSummary(io.temporal.api.common.v1.Payload value) { + public Builder setStaticSummary(Object value) { this.userMetadata = io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata) .setStaticSummary(value) @@ -410,7 +409,7 @@ public Builder setStaticSummary(io.temporal.api.common.v1.Payload value) { return this; } - public Builder setStaticDetails(io.temporal.api.common.v1.Payload value) { + public Builder setStaticDetails(Object value) { this.userMetadata = io.temporal.workflow.UserMetadata.newBuilder(this.userMetadata) .setStaticDetails(value) @@ -446,33 +445,42 @@ public SignalWithStartWorkflowRequest build() { } } - public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto() { + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest toProto( + io.temporal.common.converter.DataConverter converter) { io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest.newBuilder(); if (this.workflow != null) proto.setWorkflowType( io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeToProto( - (this.workflow))); - if (this.args != null) proto.setInput((this.args)); + converter, (this.workflow))); + if (this.args != null) + proto.setInput( + converter + .toPayloads((this.args).toArray()) + .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); if (this.id != null) proto.setWorkflowId((this.id)); if (this.taskQueue != null) proto.setTaskQueue( io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueToProto( - (this.taskQueue))); + converter, (this.taskQueue))); if (this.signal != null) proto.setSignalName((this.signal)); - if (this.signalArgs != null) proto.setSignalInput((this.signalArgs)); + if (this.signalArgs != null) + proto.setSignalInput( + converter + .toPayloads((this.signalArgs).toArray()) + .orElse(io.temporal.api.common.v1.Payloads.getDefaultInstance())); if (this.executionTimeout != null) proto.setWorkflowExecutionTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - (this.executionTimeout))); + converter, (this.executionTimeout))); if (this.runTimeout != null) proto.setWorkflowRunTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - (this.runTimeout))); + converter, (this.runTimeout))); if (this.taskTimeout != null) proto.setWorkflowTaskTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - (this.taskTimeout))); + converter, (this.taskTimeout))); if (this.idReusePolicy != null) proto.setWorkflowIdReusePolicy( io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( @@ -484,53 +492,74 @@ public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionReques if (this.retryPolicy != null) proto.setRetryPolicy( io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyToProto( - (this.retryPolicy))); + converter, (this.retryPolicy))); if (this.cronSchedule != null) proto.setCronSchedule((this.cronSchedule)); - if (this.memo != null) proto.setMemo((this.memo)); - if (this.searchAttributes != null) proto.setSearchAttributes((this.searchAttributes)); + if (this.memo != null) + proto.setMemo( + io.temporal.internal.nexus.system.TemporalModelConverters.memoToProto( + converter, (this.memo))); + if (this.searchAttributes != null) + proto.setSearchAttributes( + io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesToProto( + converter, (this.searchAttributes))); if (this.priority != null) proto.setPriority( io.temporal.internal.nexus.system.TemporalModelConverters.priorityToProto( - (this.priority))); + converter, (this.priority))); if (this.versioningOverride != null) proto.setVersioningOverride( io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideToProto( - (this.versioningOverride))); + converter, (this.versioningOverride))); if (this.startDelay != null) proto.setWorkflowStartDelay( io.temporal.internal.nexus.system.TemporalModelConverters.durationToProto( - (this.startDelay))); - if (this.userMetadata != null) proto.setUserMetadata((this.userMetadata).toProto()); + converter, (this.startDelay))); + if (this.userMetadata != null) proto.setUserMetadata((this.userMetadata).toProto(converter)); if (this.namespace != null) proto.setNamespace((this.namespace)); - if (this.headers != null) proto.setHeader((this.headers)); + if (this.headers != null) + proto.setHeader( + io.temporal.internal.nexus.system.TemporalModelConverters.headerToProto( + converter, (this.headers))); return proto.build(); } public static SignalWithStartWorkflowRequest fromProto( - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { Builder builder = SignalWithStartWorkflowRequest.newBuilder(); builder.setWorkflow( io.temporal.internal.nexus.system.TemporalModelConverters.workflowTypeFromProto( - proto.getWorkflowType())); - if (proto.hasInput()) builder.setArgs(proto.getInput()); + converter, proto.getWorkflowType())); + if (proto.hasInput()) + builder.setArgs( + (java.util.List) + (Object) + io.temporal.workflow.NexgenRuntime.decodeSequence( + proto.getInput(), converter, Object.class, Object.class)); builder.setId(proto.getWorkflowId()); builder.setTaskQueue( io.temporal.internal.nexus.system.TemporalModelConverters.taskQueueFromProto( - proto.getTaskQueue())); + converter, proto.getTaskQueue())); builder.setSignal(proto.getSignalName()); - if (proto.hasSignalInput()) builder.setSignalArgs(proto.getSignalInput()); + if (proto.hasSignalInput()) + builder.setSignalArgs( + (java.util.List) + (Object) + io.temporal.workflow.NexgenRuntime.decodeSequence( + proto.getSignalInput(), converter, Object.class, Object.class)); if (proto.hasWorkflowExecutionTimeout()) builder.setExecutionTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - proto.getWorkflowExecutionTimeout())); + converter, proto.getWorkflowExecutionTimeout())); if (proto.hasWorkflowRunTimeout()) builder.setRunTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - proto.getWorkflowRunTimeout())); + converter, proto.getWorkflowRunTimeout())); if (proto.hasWorkflowTaskTimeout()) builder.setTaskTimeout( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - proto.getWorkflowTaskTimeout())); + converter, proto.getWorkflowTaskTimeout())); builder.setIdReusePolicy( io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber( (proto.getWorkflowIdReusePolicy()).getNumber())); @@ -540,26 +569,37 @@ public static SignalWithStartWorkflowRequest fromProto( if (proto.hasRetryPolicy()) builder.setRetryPolicy( io.temporal.internal.nexus.system.TemporalModelConverters.retryPolicyFromProto( - proto.getRetryPolicy())); + converter, proto.getRetryPolicy())); builder.setCronSchedule(proto.getCronSchedule()); - if (proto.hasMemo()) builder.setMemo(proto.getMemo()); - if (proto.hasSearchAttributes()) builder.setSearchAttributes(proto.getSearchAttributes()); + if (proto.hasMemo()) + builder.setMemo( + io.temporal.internal.nexus.system.TemporalModelConverters.memoFromProto( + converter, proto.getMemo())); + if (proto.hasSearchAttributes()) + builder.setSearchAttributes( + io.temporal.internal.nexus.system.TemporalModelConverters.searchAttributesFromProto( + converter, proto.getSearchAttributes())); if (proto.hasPriority()) builder.setPriority( io.temporal.internal.nexus.system.TemporalModelConverters.priorityFromProto( - proto.getPriority())); + converter, proto.getPriority())); if (proto.hasVersioningOverride()) builder.setVersioningOverride( io.temporal.internal.nexus.system.TemporalModelConverters.versioningOverrideFromProto( - proto.getVersioningOverride())); + converter, proto.getVersioningOverride())); if (proto.hasWorkflowStartDelay()) builder.setStartDelay( io.temporal.internal.nexus.system.TemporalModelConverters.durationFromProto( - proto.getWorkflowStartDelay())); + converter, proto.getWorkflowStartDelay())); if (proto.hasUserMetadata()) - builder.setUserMetadata(io.temporal.workflow.UserMetadata.fromProto(proto.getUserMetadata())); + builder.setUserMetadata( + io.temporal.workflow.UserMetadata.fromProto( + proto.getUserMetadata(), converter, io.temporal.workflow.UserMetadata.class)); builder.setNamespace(proto.getNamespace()); - if (proto.hasHeader()) builder.setHeaders(proto.getHeader()); + if (proto.hasHeader()) + builder.setHeaders( + io.temporal.internal.nexus.system.TemporalModelConverters.headerFromProto( + converter, proto.getHeader())); return builder.build(); } @@ -571,7 +611,10 @@ public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) } public Object toTransferType(SignalWithStartWorkflowRequest value) { - return value == null ? null : value.toProto(); + return value == null + ? null + : value.toProto( + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); } public SignalWithStartWorkflowRequest fromTransferType( @@ -579,7 +622,9 @@ public SignalWithStartWorkflowRequest fromTransferType( return value == null ? null : fromProto( - (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value); + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest) value, + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), + valueType); } } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java index 7b21db85fe..a433bec3b8 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowResponse.java @@ -68,7 +68,8 @@ public SignalWithStartWorkflowResponse build() { } } - public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto() { + public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse toProto( + io.temporal.common.converter.DataConverter converter) { io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.Builder proto = io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse.newBuilder(); if (this.runId != null) proto.setRunId((this.runId)); @@ -77,7 +78,9 @@ public io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRespon } public static SignalWithStartWorkflowResponse fromProto( - io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto) { + io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { Builder builder = SignalWithStartWorkflowResponse.newBuilder(); builder.setRunId(proto.getRunId()); builder.setStarted(proto.getStarted()); @@ -92,7 +95,10 @@ public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) } public Object toTransferType(SignalWithStartWorkflowResponse value) { - return value == null ? null : value.toProto(); + return value == null + ? null + : value.toProto( + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); } public SignalWithStartWorkflowResponse fromTransferType( @@ -100,7 +106,9 @@ public SignalWithStartWorkflowResponse fromTransferType( return value == null ? null : fromProto( - (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value); + (io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse) value, + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), + valueType); } } } diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java index ebb3f47c30..5f46870136 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/UserMetadata.java @@ -9,30 +9,28 @@ public final class UserMetadata { * Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be * in single-line Temporal Markdown format. */ - private final io.temporal.api.common.v1.Payload staticSummary; + private final Object staticSummary; /** * General fixed details for the workflow execution that may appear in UI and CLI. This can be in * Temporal Markdown format and can span multiple lines. This value is fixed on the workflow * execution and cannot be updated. */ - private final io.temporal.api.common.v1.Payload staticDetails; + private final Object staticDetails; @com.fasterxml.jackson.annotation.JsonCreator public UserMetadata( - @com.fasterxml.jackson.annotation.JsonProperty("staticSummary") - io.temporal.api.common.v1.Payload staticSummary, - @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") - io.temporal.api.common.v1.Payload staticDetails) { + @com.fasterxml.jackson.annotation.JsonProperty("staticSummary") Object staticSummary, + @com.fasterxml.jackson.annotation.JsonProperty("staticDetails") Object staticDetails) { this.staticSummary = staticSummary; this.staticDetails = staticDetails; } - public io.temporal.api.common.v1.Payload getStaticSummary() { + public Object getStaticSummary() { return staticSummary; } - public io.temporal.api.common.v1.Payload getStaticDetails() { + public Object getStaticDetails() { return staticDetails; } @@ -57,16 +55,16 @@ private Builder(UserMetadata value) { this.staticDetails = value.staticDetails; } - private io.temporal.api.common.v1.Payload staticSummary = null; + private Object staticSummary = null; - public Builder setStaticSummary(io.temporal.api.common.v1.Payload value) { + public Builder setStaticSummary(Object value) { this.staticSummary = value; return this; } - private io.temporal.api.common.v1.Payload staticDetails = null; + private Object staticDetails = null; - public Builder setStaticDetails(io.temporal.api.common.v1.Payload value) { + public Builder setStaticDetails(Object value) { this.staticDetails = value; return this; } @@ -76,18 +74,28 @@ public UserMetadata build() { } } - public io.temporal.api.sdk.v1.UserMetadata toProto() { + public io.temporal.api.sdk.v1.UserMetadata toProto( + io.temporal.common.converter.DataConverter converter) { io.temporal.api.sdk.v1.UserMetadata.Builder proto = io.temporal.api.sdk.v1.UserMetadata.newBuilder(); - if (this.staticSummary != null) proto.setSummary((this.staticSummary)); - if (this.staticDetails != null) proto.setDetails((this.staticDetails)); + if (this.staticSummary != null) + proto.setSummary(converter.toPayload((this.staticSummary)).get()); + if (this.staticDetails != null) + proto.setDetails(converter.toPayload((this.staticDetails)).get()); return proto.build(); } - public static UserMetadata fromProto(io.temporal.api.sdk.v1.UserMetadata proto) { + public static UserMetadata fromProto( + io.temporal.api.sdk.v1.UserMetadata proto, + io.temporal.common.converter.DataConverter converter, + java.lang.reflect.Type modelType) { Builder builder = UserMetadata.newBuilder(); - if (proto.hasSummary()) builder.setStaticSummary(proto.getSummary()); - if (proto.hasDetails()) builder.setStaticDetails(proto.getDetails()); + if (proto.hasSummary()) + builder.setStaticSummary( + (Object) converter.fromPayload(proto.getSummary(), Object.class, Object.class)); + if (proto.hasDetails()) + builder.setStaticDetails( + (Object) converter.fromPayload(proto.getDetails(), Object.class, Object.class)); return builder.build(); } @@ -98,11 +106,19 @@ public java.lang.reflect.Type getTransferType(java.lang.reflect.Type valueType) } public Object toTransferType(UserMetadata value) { - return value == null ? null : value.toProto(); + return value == null + ? null + : value.toProto( + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter()); } public UserMetadata fromTransferType(Object value, java.lang.reflect.Type valueType) { - return value == null ? null : fromProto((io.temporal.api.sdk.v1.UserMetadata) value); + return value == null + ? null + : fromProto( + (io.temporal.api.sdk.v1.UserMetadata) value, + io.temporal.internal.nexus.system.TemporalModelConverters.currentDataConverter(), + valueType); } } } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java index 93da7d2dda..7a420b642b 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/SystemNexusDataConverter.java @@ -10,14 +10,36 @@ import io.temporal.internal.common.converter.TemporalTransferTypeDataConverter; import io.temporal.internal.payload.visitor.SystemNexusPayloads; import java.lang.reflect.Type; +import java.util.Objects; import java.util.Optional; +import java.util.function.Supplier; import javax.annotation.Nonnull; /** Keeps the server-readable envelope separate from the destination workflow's user converter. */ public final class SystemNexusDataConverter implements DataConverter { public static final String ENDPOINT = "__temporal_system"; + private static final ThreadLocal USER_CONVERTER = new ThreadLocal<>(); private final DataConverter userConverter; + static DataConverter currentDataConverter() { + DataConverter converter = USER_CONVERTER.get(); + if (converter == null) + throw new IllegalStateException("System Nexus user converter context is not active"); + return converter; + } + + static T withDataConverter(DataConverter converter, Supplier action) { + Objects.requireNonNull(converter, "converter"); + DataConverter previous = USER_CONVERTER.get(); + USER_CONVERTER.set(converter); + try { + return action.get(); + } finally { + if (previous == null) USER_CONVERTER.remove(); + else USER_CONVERTER.set(previous); + } + } + public SystemNexusDataConverter(DataConverter userConverter) { this.userConverter = userConverter; } @@ -25,23 +47,33 @@ public SystemNexusDataConverter(DataConverter userConverter) { @Override public Optional toPayload(T value) { if (value instanceof RawValue) return Optional.of(((RawValue) value).getPayload()); - Object transferred = TemporalTransferTypeDataConverter.toTransferValue(value); - if (!(transferred instanceof Message)) - throw new DataConverterException("System Nexus inputs must have a protobuf transfer type"); - return Optional.of(SystemNexusPayloads.pack((Message) transferred)); + return withDataConverter( + userConverter, + () -> { + Object transferred = TemporalTransferTypeDataConverter.toTransferValue(value); + if (!(transferred instanceof Message)) + throw new DataConverterException( + "System Nexus inputs must have a protobuf transfer type"); + return Optional.of(SystemNexusPayloads.pack((Message) transferred)); + }); } @Override public T fromPayload(Payload payload, Class valueClass, Type valueType) { if (valueClass == RawValue.class) return valueClass.cast(new RawValue(payload)); - Message value = SystemNexusPayloads.unpack(payload).build(); - TemporalTransferTypeDataConverter.TransferType transfer = - TemporalTransferTypeDataConverter.transferTypeFor(valueClass, valueType); - if (transfer == null) return valueClass.cast(value); - if (!transfer.getRawType().isInstance(value)) - throw new DataConverterException( - "Unexpected system Nexus response type: " + value.getDescriptorForType().getFullName()); - return transfer.fromValue(value, valueClass); + return withDataConverter( + userConverter, + () -> { + Message value = SystemNexusPayloads.unpack(payload).build(); + TemporalTransferTypeDataConverter.TransferType transfer = + TemporalTransferTypeDataConverter.transferTypeFor(valueClass, valueType); + if (transfer == null) return valueClass.cast(value); + if (!transfer.getRawType().isInstance(value)) + throw new DataConverterException( + "Unexpected system Nexus response type: " + + value.getDescriptorForType().getFullName()); + return transfer.fromValue(value, valueClass); + }); } @Override diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java index 1ab902c1f9..57825ebcef 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -1,23 +1,27 @@ package io.temporal.internal.nexus.system; -import io.temporal.api.common.v1.Priority; -import io.temporal.api.common.v1.RetryPolicy; -import io.temporal.api.common.v1.WorkflowType; +import io.temporal.api.common.v1.*; import io.temporal.api.taskqueue.v1.TaskQueue; import io.temporal.common.RetryOptions; import io.temporal.common.VersioningOverride; -import io.temporal.internal.common.ProtoConverters; -import io.temporal.internal.common.ProtobufTimeUtils; -import io.temporal.internal.common.RetryOptionsUtils; +import io.temporal.common.converter.DataConverter; +import io.temporal.internal.common.*; import io.temporal.payload.context.WorkflowSerializationContext; import io.temporal.workflow.SignalWithStartWorkflowRequest; import io.temporal.workflow.Workflow; import java.time.Duration; +import java.util.LinkedHashMap; +import java.util.Map; -/** SDK-owned structural conversion hooks used by the generated system Nexus bindings. */ +/** SDK-owned model conversion hooks used by the generated system Nexus bindings. */ public final class TemporalModelConverters { private TemporalModelConverters() {} + /** Returns the user converter active during system Nexus transfer conversion. */ + public static DataConverter currentDataConverter() { + return SystemNexusDataConverter.currentDataConverter(); + } + public static String workflowNamespace() { return Workflow.getInfo().getNamespace(); } @@ -27,54 +31,121 @@ public static WorkflowSerializationContext signalWithStartWorkflowSerializationC return new WorkflowSerializationContext(request.getNamespace(), request.getId()); } - public static WorkflowType workflowTypeToProto(String value) { + public static RuntimeException failureFromProto( + DataConverter converter, io.temporal.api.failure.v1.Failure value) { + return converter.failureToException(value); + } + + public static io.temporal.api.failure.v1.Failure failureToProto( + DataConverter converter, RuntimeException value) { + return converter.exceptionToFailure(value); + } + + public static WorkflowType workflowTypeToProto(DataConverter converter, String value) { return WorkflowType.newBuilder().setName(value).build(); } - public static String workflowTypeFromProto(WorkflowType value) { + public static String workflowTypeFromProto(DataConverter converter, WorkflowType value) { return value.getName(); } - public static TaskQueue taskQueueToProto(String value) { + public static TaskQueue taskQueueToProto(DataConverter converter, String value) { return TaskQueue.newBuilder().setName(value).build(); } - public static String taskQueueFromProto(TaskQueue value) { + public static String taskQueueFromProto(DataConverter converter, TaskQueue value) { return value.getName(); } - public static com.google.protobuf.Duration durationToProto(Duration value) { + public static com.google.protobuf.Duration durationToProto( + DataConverter converter, Duration value) { return ProtobufTimeUtils.toProtoDuration(value); } - public static Duration durationFromProto(com.google.protobuf.Duration value) { + public static Duration durationFromProto( + DataConverter converter, com.google.protobuf.Duration value) { return ProtobufTimeUtils.toJavaDuration(value); } - public static RetryPolicy retryPolicyToProto(RetryOptions value) { + public static RetryPolicy retryPolicyToProto(DataConverter converter, RetryOptions value) { return RetryOptionsUtils.toRetryPolicy(value).build(); } - public static RetryOptions retryPolicyFromProto(RetryPolicy value) { + public static RetryOptions retryPolicyFromProto(DataConverter converter, RetryPolicy value) { return RetryOptionsUtils.toRetryOptions(value); } - public static Priority priorityToProto(io.temporal.common.Priority value) { + public static Memo memoToProto(DataConverter converter, Map value) { + Memo.Builder builder = Memo.newBuilder(); + value.forEach((key, item) -> builder.putFields(key, converter.toPayload(item).get())); + return builder.build(); + } + + public static Map memoFromProto(DataConverter converter, Memo value) { + Map result = new LinkedHashMap<>(); + value + .getFieldsMap() + .forEach( + (key, payload) -> + result.put(key, converter.fromPayload(payload, Object.class, Object.class))); + return result; + } + + public static Header headerToProto(DataConverter converter, Map value) { + Header.Builder builder = Header.newBuilder(); + value.forEach( + (key, payload) -> + builder.putFields( + key, + converter.toPayload(new io.temporal.common.converter.RawValue(payload)).get())); + return builder.build(); + } + + public static Map headerFromProto(DataConverter converter, Header value) { + Map result = new LinkedHashMap<>(); + value + .getFieldsMap() + .forEach( + (key, payload) -> + result.put( + key, + converter + .fromPayload( + payload, + io.temporal.common.converter.RawValue.class, + io.temporal.common.converter.RawValue.class) + .getPayload())); + return result; + } + + public static io.temporal.api.common.v1.SearchAttributes searchAttributesToProto( + DataConverter converter, io.temporal.common.SearchAttributes value) { + return SearchAttributesUtil.encodeTyped(value); + } + + public static io.temporal.common.SearchAttributes searchAttributesFromProto( + DataConverter converter, io.temporal.api.common.v1.SearchAttributes value) { + return SearchAttributesUtil.decodeTyped(value); + } + + public static Priority priorityToProto( + DataConverter converter, io.temporal.common.Priority value) { return ProtoConverters.toProto(value); } - public static io.temporal.common.Priority priorityFromProto(Priority value) { + public static io.temporal.common.Priority priorityFromProto( + DataConverter converter, Priority value) { return ProtoConverters.fromProto(value); } public static io.temporal.api.workflow.v1.VersioningOverride versioningOverrideToProto( - VersioningOverride value) { + DataConverter converter, VersioningOverride value) { return ProtoConverters.toProto(value); } @SuppressWarnings("deprecation") public static VersioningOverride versioningOverrideFromProto( - io.temporal.api.workflow.v1.VersioningOverride value) { + DataConverter converter, io.temporal.api.workflow.v1.VersioningOverride value) { if (value.hasOneTime()) return new VersioningOverride.OneTimeVersioningOverride( deployment(value.getOneTime().getTargetDeploymentVersion())); diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index e6188cce61..79855f808f 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -31,17 +31,16 @@ to match the SDK's Spotless configuration. Nex-gen downloads and caches its standalone JAR on first use; for offline regeneration, set `NEXGEN_JAVA_FORMAT_JAR` to a local all-dependencies JAR. A JDK must be on `PATH`. -`TemporalModelConverters` contains SDK-owned structural conversion helpers. -Generated models preserve embedded payloads, batches, memo, headers, search -attributes, and failure details in serialized form. Transfer conversion copies -them without invoking a user converter or needing type hints. These bindings -require no `NexgenRuntime` or converter scope. API code serializes user values -when constructing a request and supplies expected types when decoding results. +`TemporalModelConverters` contains the SDK-owned conversion helpers. The emitted +`NexgenRuntime` contains only payload-sequence decoding. Converter scoping lives +in `SystemNexusDataConverter`; generated transfer converters obtain the active +converter through `TemporalModelConverters.currentDataConverter()` and fail +when no scope is active, matching Python. Protobuf field access is generated +directly. Nex-gen assembles the required runtime helpers from Rust strings. Normal Java SDK builds do not require Rust or nex-gen. The SDK wraps any configured `DataConverter` in `SystemNexusDataConverter` for -system operations. That wrapper handles the outer envelope; embedded values are -already serialized. It delegates operation failure conversion to the configured -converter. Custom converters do not need to recognize system envelopes. +system operations. That wrapper handles the outer envelope and delegates nested +user conversion; custom converters do not need to recognize system envelopes. The shared payload visitor descends into marked envelopes for payload traversal. `CodecDataConverter` contains no system Nexus handling. diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md index aa45582e56..068a9d73ce 100644 --- a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -1,46 +1,34 @@ # Signal with start inside workflows -The generated workflow operation atomically signals an external workflow, -starting it when necessary. It requires a server supporting the system workflow -service. Its request model is a low-level serialized representation; an ergonomic -API with required parameters and options containing user values is future work. - -Request construction must serialize user values with the configured converter -and destination workflow context. Given that converter as `configuredConverter`: +The generated workflow API atomically signals an external workflow, starting it +when necessary. It requires a server supporting the system workflow service. ```java -String namespace = Workflow.getInfo().getNamespace(); -String workflowId = "target"; -DataConverter converter = configuredConverter.withContext( - new WorkflowSerializationContext(namespace, workflowId)); ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( SignalWithStartWorkflowRequest.newBuilder() .setWorkflow("TargetWorkflow") .setSignal("notify") - .setId(workflowId) - .setNamespace(namespace) + .setId("target") .setTaskQueue("target-queue") - .setArgs(converter.toPayloads(input).get()) - .setSignalArgs(converter.toPayloads(signal).get()) + .setArgs(Collections.singletonList(input)) + .setSignalArgs(Collections.singletonList(signal)) .build()); ``` Import `Workflow`, `SignalWithStartWorkflowRequest`, and `ExternalWorkflowStub` -from `io.temporal.workflow`, `DataConverter` from -`io.temporal.common.converter`, and `WorkflowSerializationContext` from -`io.temporal.payload.context`. Payload-bearing fields, including memo, headers, -static summary/details, and search attributes, retain serialized protobuf values. -The generated builder also carries timeouts, retry policy, and conflict policy. -Namespace defaults to the caller's namespace. Request ID is omitted: the system -service manages it. +from `io.temporal.workflow`. The generated request builder contains the API's +options, including timeouts, retry policy, memo, conflict policy, and flattened +static summary/details setters. Workflow ID and task queue are explicit request +fields. Namespace defaults to the caller's namespace. Request ID is omitted: +the system service manages it. The call returns after signal delivery/start completes. The returned external stub supports further signals and cancellation. Use `Async.function(Workflow::signalWithStartWorkflow, request)` for a promise. `Workflow` inherits generated operations from `WorkflowOperations`. New WIT -operations become available after regeneration. The output transform, request -fields, and serialization-context hook are declared in WIT. Transfer conversion -preserves serialized payloads and whole batches without decoding them. Future -typed APIs can decode embedded results with their expected types. The outer -system envelope remains server-readable. +operations become available after regeneration, without adding handwritten +options, capture proxies, stubs, or facade methods. The output transform, request +fields, and serialization-context hook are declared in WIT. The converter uses +the destination namespace and workflow ID for nested payloads, codecs, and +failures; the outer system envelope remains server-readable. diff --git a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit index b0d117a6c2..5a61e9de2d 100644 --- a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit +++ b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit @@ -6,7 +6,7 @@ interface model { /// @nexus.proto "temporal.api.common.v1.Payload" typescript-import="@temporalio/proto" /// @nexus.type - /// java="io.temporal.api.common.v1.Payload" + /// java="Object" /// python="typing.Any" /// typescript="common.Payload" /// go="any" @@ -19,18 +19,20 @@ interface model { /// @nexus.proto "temporal.api.common.v1.Payloads" /// typescript-import="@temporalio/proto" /// @nexus.type - /// java="io.temporal.api.common.v1.Payloads" + /// java="java.util.List" /// go="[]any" /// dotnet="IReadOnlyCollection" /// dotnet-from="ProtoExtensions.FromPayloads" /// dotnet-to="ProtoExtensions.ToPayloads" type payloads = list; - /// Temporal failure represented by a serialized protobuf or SDK-native error. - /// The surrounding SDK API owns payload serialization and typed decoding. + /// Temporal failure represented by the target SDK's native exception/error type. + /// The SDK failure converter owns the recursive cause and failure-info structure. /// @nexus.proto "temporal.api.failure.v1.Failure" typescript-import="@temporalio/proto" /// @nexus.type - /// java="io.temporal.api.failure.v1.Failure" + /// java="RuntimeException" + /// java-from="failureFromProto" + /// java-to="failureToProto" /// python="BaseException" /// typescript="Error" /// go="error" @@ -136,7 +138,9 @@ interface model { /// @nexus.proto "temporal.api.common.v1.Memo" typescript-import="@temporalio/proto" /// @nexus.type - /// java="io.temporal.api.common.v1.Memo" + /// java="java.util.Map" + /// java-from="memoFromProto" + /// java-to="memoToProto" /// python="collections.abc.Mapping[str, typing.Any]" /// typescript="Record" /// go="map[string]any" @@ -146,7 +150,9 @@ interface model { /// @nexus.proto "temporal.api.common.v1.Header" typescript-import="@temporalio/proto" /// @nexus.type - /// java="io.temporal.api.common.v1.Header" + /// java="java.util.Map" + /// java-from="headerFromProto" + /// java-to="headerToProto" /// python="collections.abc.Mapping[str, typing.Any]" /// typescript="common.Headers" /// go="map[string]any" @@ -158,7 +164,9 @@ interface model { /// @nexus.proto "temporal.api.common.v1.SearchAttributes" typescript-import="@temporalio/proto" /// @nexus.type - /// java="io.temporal.api.common.v1.SearchAttributes" + /// java="io.temporal.common.SearchAttributes" + /// java-from="searchAttributesFromProto" + /// java-to="searchAttributesToProto" /// python="temporalio.common.TypedSearchAttributes" /// typescript="common.TypedSearchAttributes" /// go="go.temporal.io/sdk/temporal.SearchAttributes" diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java index f44a8551bd..04fedd2700 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/SystemNexusDataConverterTest.java @@ -1,13 +1,11 @@ package io.temporal.internal.nexus.system; import static org.junit.Assert.*; +import static org.mockito.AdditionalAnswers.delegatesTo; import static org.mockito.Mockito.*; import com.google.protobuf.ByteString; -import io.temporal.api.common.v1.Header; -import io.temporal.api.common.v1.Memo; import io.temporal.api.common.v1.Payload; -import io.temporal.api.common.v1.Payloads; import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest; import io.temporal.common.converter.*; import io.temporal.internal.payload.visitor.SystemNexusPayloads; @@ -25,38 +23,19 @@ public class SystemNexusDataConverterTest { private static final String OPERATION = "SignalWithStartWorkflowExecution"; private static SignalWithStartWorkflowRequest request(String id) { - return request(id, DefaultDataConverter.STANDARD_INSTANCE); - } - - private static SignalWithStartWorkflowRequest request(String id, DataConverter converter) { return SignalWithStartWorkflowRequest.newBuilder() .setNamespace("destination") .setId(id) .setWorkflow("Target") .setTaskQueue("queue") .setSignal("notify") - .setArgs(converter.toPayloads("workflow", 42).get()) - .setSignalArgs(converter.toPayloads("signal").get()) - .setMemo(Memo.newBuilder().putFields("memo", converter.toPayload("value").get()).build()) + .setArgs(Arrays.asList("workflow", 42)) + .setSignalArgs(Collections.singletonList("signal")) + .setMemo(Collections.singletonMap("memo", "value")) .setHeaders( - Header.newBuilder() - .putFields("trace", converter.toPayload("trace-value").get()) - .build()) - .setUserMetadata( - UserMetadata.newBuilder() - .setStaticSummary(converter.toPayload("summary").get()) - .setStaticDetails(converter.toPayload("details").get()) - .build()) - .setSearchAttributes( - io.temporal.api.common.v1.SearchAttributes.newBuilder() - .putIndexedFields( - "key", - Payload.newBuilder() - .putMetadata( - "encoding", ByteString.copyFromUtf8("unknown/search-attribute")) - .setData(ByteString.copyFromUtf8("opaque")) - .build()) - .build()) + Collections.singletonMap( + "trace", DefaultDataConverter.STANDARD_INSTANCE.toPayload("trace-value").get())) + .setUserMetadata(UserMetadata.newBuilder().setStaticSummary("summary").build()) .build(); } @@ -85,19 +64,17 @@ public void decodesUnmarkedServerResponse() { @Test public void nestedPayloadsUseDestinationContextAndOuterEnvelopeBypassesCodecs() throws Exception { + SignalWithStartWorkflowRequest request = request("target"); WorkflowSerializationContext context = - new WorkflowSerializationContext("destination", "target"); + (WorkflowSerializationContext) + SystemNexusOperations.serializationContext(SERVICE, OPERATION, request); + assertEquals("destination", context.getNamespace()); + assertEquals("target", context.getWorkflowId()); DataConverter user = new CodecDataConverter( DefaultDataConverter.STANDARD_INSTANCE, Collections.singletonList(new ContextCodec(null))) .withContext(context); - SignalWithStartWorkflowRequest request = request("target", user); - WorkflowSerializationContext acquired = - (WorkflowSerializationContext) - SystemNexusOperations.serializationContext(SERVICE, OPERATION, request); - assertEquals("destination", acquired.getNamespace()); - assertEquals("target", acquired.getWorkflowId()); SystemNexusDataConverter converter = new SystemNexusDataConverter(user); Payload encoded = converter.toPayload(request).get(); assertTrue(SystemNexusPayloads.isSystemPayload(encoded)); @@ -120,30 +97,32 @@ public void nestedPayloadsUseDestinationContextAndOuterEnvelopeBypassesCodecs() assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); assertEquals(request.getMemo(), decoded.getMemo()); assertEquals(request.getHeaders(), decoded.getHeaders()); - assertEquals(request.getSearchAttributes(), decoded.getSearchAttributes()); - assertEquals( - request.getUserMetadata().getStaticDetails(), decoded.getUserMetadata().getStaticDetails()); assertEquals( "target", wire.getHeader() .getFieldsOrThrow("trace") .getMetadataOrThrow("test-context") .toStringUtf8()); - assertEquals( - "summary", - user.fromPayload(decoded.getUserMetadata().getStaticSummary(), String.class, String.class)); + assertEquals("summary", decoded.getUserMetadata().getStaticSummary()); } @Test - public void transferConversionDoesNotUseTheUserConverter() throws Exception { + public void customDataConverterReceivesUserValuesWithoutSystemEnvelopeHandling() + throws Exception { SignalWithStartWorkflowRequest request = request("target"); - DataConverter user = mock(DataConverter.class); + DataConverter user = + mock(DataConverter.class, delegatesTo(DefaultDataConverter.STANDARD_INSTANCE)); SystemNexusDataConverter converter = new SystemNexusDataConverter(user); Payload encoded = converter.toPayload(request).get(); assertTrue(SystemNexusPayloads.isSystemPayload(encoded)); SignalWithStartWorkflowExecutionRequest wire = SignalWithStartWorkflowExecutionRequest.parseFrom(encoded.getData()); assertEquals("target", wire.getWorkflowId()); + verify(user).toPayloads("workflow", 42); + verify(user).toPayloads("signal"); + verify(user).toPayload("value"); + verify(user, never()).toPayload(request); + verify(user, never()).toPayload(isA(com.google.protobuf.Message.class)); SignalWithStartWorkflowRequest decoded = converter.fromPayload( encoded, SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class); @@ -151,11 +130,10 @@ public void transferConversionDoesNotUseTheUserConverter() throws Exception { assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); assertEquals(request.getMemo(), decoded.getMemo()); assertEquals(request.getHeaders(), decoded.getHeaders()); - verifyNoInteractions(user); } @Test - public void responseAndRawValuesRoundTrip() { + public void responseAndRawValuesRoundTripAndConverterScopesRestore() { SystemNexusDataConverter converter = new SystemNexusDataConverter(DefaultDataConverter.STANDARD_INSTANCE); SignalWithStartWorkflowResponse response = @@ -170,32 +148,57 @@ public void responseAndRawValuesRoundTrip() { SignalWithStartWorkflowResponse.class) .getRunId()); assertSame(encoded, converter.toPayload(new RawValue(encoded)).get()); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); } @Test - public void transferConversionRequiresNoConverterContextOrTypeHints() { + public void converterScopesRestoreAfterNestedFailure() { + DataConverter outer = DefaultDataConverter.STANDARD_INSTANCE; + DataConverter inner = new DefaultDataConverter(); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + SystemNexusDataConverter.withDataConverter( + outer, + () -> { + assertSame(outer, TemporalModelConverters.currentDataConverter()); + assertThrows( + IllegalArgumentException.class, + () -> + SystemNexusDataConverter.withDataConverter( + inner, + () -> { + assertSame(inner, TemporalModelConverters.currentDataConverter()); + throw new IllegalArgumentException("test"); + })); + assertSame(outer, TemporalModelConverters.currentDataConverter()); + return null; + }); + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); + } + + @Test + public void transferConversionRequiresActiveUserConverter() { SignalWithStartWorkflowRequest.Converter converter = new SignalWithStartWorkflowRequest.Converter(); - SignalWithStartWorkflowRequest request = request("target"); - SignalWithStartWorkflowRequest decoded = - converter.fromTransferType( - converter.toTransferType(request), SignalWithStartWorkflowRequest.class); - assertEquals(request.getArgs(), decoded.getArgs()); - assertEquals(request.getMemo(), decoded.getMemo()); + IllegalStateException encodeFailure = + assertThrows( + IllegalStateException.class, () -> converter.toTransferType(request("target"))); + assertEquals("System Nexus user converter context is not active", encodeFailure.getMessage()); + assertThrows( + IllegalStateException.class, + () -> + converter.fromTransferType( + SignalWithStartWorkflowExecutionRequest.getDefaultInstance(), + SignalWithStartWorkflowRequest.class)); } @Test - public void requestsRetainIndependentlySerializedDestinationPayloads() { + public void operationsRetainIndependentDestinationConverters() { + SignalWithStartWorkflowRequest first = request("first"); + SignalWithStartWorkflowRequest second = request("second"); DataConverter base = new CodecDataConverter( DefaultDataConverter.STANDARD_INSTANCE, Collections.singletonList(new ContextCodec(null))); - SignalWithStartWorkflowRequest first = - request( - "first", base.withContext(new WorkflowSerializationContext("destination", "first"))); - SignalWithStartWorkflowRequest second = - request( - "second", base.withContext(new WorkflowSerializationContext("destination", "second"))); SystemNexusDataConverter firstConverter = new SystemNexusDataConverter( base.withContext( @@ -206,11 +209,6 @@ public void requestsRetainIndependentlySerializedDestinationPayloads() { SystemNexusOperations.serializationContext(SERVICE, OPERATION, second))); Payload firstPayload = firstConverter.toPayload(first).get(); Payload secondPayload = secondConverter.toPayload(second).get(); - assertEquals( - "first", first.getArgs().getPayloads(0).getMetadataOrThrow("test-context").toStringUtf8()); - assertEquals( - "second", - second.getArgs().getPayloads(0).getMetadataOrThrow("test-context").toStringUtf8()); assertEquals( "second", secondConverter @@ -227,58 +225,7 @@ public void requestsRetainIndependentlySerializedDestinationPayloads() { SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class) .getId()); - } - - @Test - public void packedSequencesStayOpaqueUntilTheCallerDecodesWithKnownTypes() { - DataConverter user = - new CodecDataConverter( - DefaultDataConverter.STANDARD_INSTANCE, Collections.singletonList(new PackingCodec())); - SignalWithStartWorkflowRequest request = request("target", user); - assertEquals(1, request.getArgs().getPayloadsCount()); - SystemNexusDataConverter converter = new SystemNexusDataConverter(mock(DataConverter.class)); - Payload envelope = converter.toPayload(request).get(); - SignalWithStartWorkflowRequest decoded = - converter.fromPayload( - envelope, SignalWithStartWorkflowRequest.class, SignalWithStartWorkflowRequest.class); - assertEquals(request.getArgs(), decoded.getArgs()); - assertEquals(request.getSignalArgs(), decoded.getSignalArgs()); - assertEquals(request.getMemo(), decoded.getMemo()); - assertEquals( - request.getUserMetadata().getStaticSummary(), decoded.getUserMetadata().getStaticSummary()); - assertArrayEquals( - new Object[] {"workflow", 42}, - user.fromPayloads( - Optional.of(decoded.getArgs()), - new Class[] {String.class, Integer.class}, - new java.lang.reflect.Type[] {String.class, Integer.class})); - } - - private static final class PackingCodec implements PayloadCodec { - @Nonnull - @Override - public List encode(@Nonnull List values) { - return Collections.singletonList( - Payload.newBuilder() - .putMetadata("encoding", ByteString.copyFromUtf8("test/packed")) - .setData(Payloads.newBuilder().addAllPayloads(values).build().toByteString()) - .build()); - } - - @Nonnull - @Override - public List decode(@Nonnull List values) { - List decoded = new ArrayList<>(); - for (Payload value : values) { - assertEquals("test/packed", value.getMetadataOrThrow("encoding").toStringUtf8()); - try { - decoded.addAll(Payloads.parseFrom(value.getData()).getPayloadsList()); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw new AssertionError(e); - } - } - return decoded; - } + assertThrows(IllegalStateException.class, TemporalModelConverters::currentDataConverter); } @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java index fd37a4f005..d03bb45a9c 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.*; -import io.temporal.common.converter.DefaultDataConverter; import io.temporal.common.interceptors.*; import io.temporal.testing.internal.SDKTestWorkflowRule; import io.temporal.worker.WorkerFactoryOptions; @@ -44,20 +43,8 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { request.getNamespace()); assertEquals("notify", request.getSignal()); assertEquals("queue", request.getTaskQueue()); - assertEquals( - "input", - DefaultDataConverter.STANDARD_INSTANCE.fromPayloads( - 0, - java.util.Optional.of(request.getArgs()), - String.class, - String.class)); - assertEquals( - "signal", - DefaultDataConverter.STANDARD_INSTANCE.fromPayloads( - 0, - java.util.Optional.of(request.getSignalArgs()), - String.class, - String.class)); + assertEquals("input", request.getArgs().get(0)); + assertEquals("signal", request.getSignalArgs().get(0)); return new ExecuteNexusOperationOutput<>( Workflow.newPromise( SignalWithStartWorkflowResponse.newBuilder() @@ -93,8 +80,8 @@ public String run() { .setSignal("notify") .setId("sync") .setTaskQueue("queue") - .setArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("input").get()) - .setSignalArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("signal").get()) + .setArgs(java.util.Collections.singletonList("input")) + .setSignalArgs(java.util.Collections.singletonList("signal")) .build(); ExternalWorkflowStub sync = Workflow.signalWithStartWorkflow(request); ExternalWorkflowStub async = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java index 1d78c9b9b2..ec54c2e571 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -3,7 +3,6 @@ import static org.junit.Assert.assertEquals; import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; -import io.temporal.common.converter.DefaultDataConverter; import io.temporal.testing.CloudTestExclusion.RequiresCloudProvisioning; import io.temporal.testing.CloudTestExclusionNote; import io.temporal.testing.WorkflowReplayer; @@ -83,16 +82,16 @@ public String run() { .setTaskQueue(Workflow.getInfo().getTaskQueue()) .setIdConflictPolicy( WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) - .setArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("start").get()) - .setSignalArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("first").get()) + .setArgs(java.util.Collections.singletonList("start")) + .setSignalArgs(java.util.Collections.singletonList("first")) .build(); ExternalWorkflowStub external = Workflow.signalWithStartWorkflow(request); assertEquals(id, external.getExecution().getWorkflowId()); Async.function( Workflow::signalWithStartWorkflow, request.toBuilder() - .setArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("ignored").get()) - .setSignalArgs(DefaultDataConverter.STANDARD_INSTANCE.toPayloads("second").get()) + .setArgs(java.util.Collections.singletonList("ignored")) + .setSignalArgs(java.util.Collections.singletonList("second")) .build()) .get(); return id; From f2f9c90f8627f05ade02ecfc6b8aa88dc305f7ca Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Tue, 20 Oct 2026 10:50:12 -0700 Subject: [PATCH 10/17] Document generic requirements for payload-bearing responses --- temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md index 068a9d73ce..13955cda18 100644 --- a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -32,3 +32,9 @@ options, capture proxies, stubs, or facade methods. The output transform, reques fields, and serialization-context hook are declared in WIT. The converter uses the destination namespace and workflow ID for nested payloads, codecs, and failures; the outer system envelope remains server-readable. + +This operation serializes the request and deserializes a response with no user +payloads. Future operations returning embedded payloads must use generic response +models and propagate concrete result types from the API to transfer conversion. +The ergonomic API with required parameters and a user-typed options struct is +separate future work. From 6073b772d55df99fa1cf9e2da36c3905954754cf Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Tue, 20 Oct 2026 11:13:59 -0700 Subject: [PATCH 11/17] Expose generated workflow arguments and options API --- CHANGELOG.md | 2 +- .../SignalWithStartWorkflowOptions.java | 349 ++++++++++++++++++ .../SignalWithStartWorkflowRequest.java | 4 +- .../temporal/workflow/WorkflowOperations.java | 53 +++ temporal-sdk/src/main/nexus/README.md | 3 +- .../src/main/nexus/SIGNAL_WITH_START.md | 25 +- .../nexus/deps/nexus-temporal-types/model.wit | 4 +- .../nexus/SignalWithStartWorkflowTest.java | 54 ++- .../SystemSignalWithStartIntegrationTest.java | 25 +- 9 files changed, 472 insertions(+), 47 deletions(-) create mode 100644 temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f3e5554dd9..5fcf2c5dbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ to docs, or any other relevant information. ### Added - Workflows can signal with start through the system workflow service using - generated `Workflow.signalWithStartWorkflow(SignalWithStartWorkflowRequest)` API. + generated `Workflow.signalWithStartWorkflow(workflowType, workflowId, taskQueue, signalName, options)` API. Request builders and operations are generated into `io.temporal.workflow`. System Nexus envelopes preserve destination workflow serialization context for nested payloads, codecs, and external payload storage. Requires a server supporting the system workflow service. diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java new file mode 100644 index 0000000000..7c37993610 --- /dev/null +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java @@ -0,0 +1,349 @@ +// Generated by nexgen v0.2.9. DO NOT EDIT! +package io.temporal.workflow; + +/** Signal a workflow, starting it first if needed. */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class SignalWithStartWorkflowOptions { + /** Arguments for the workflow. */ + private final java.util.List args; + + /** Arguments for the signal. */ + private final java.util.List signalArgs; + + /** + * Total workflow execution timeout, including retries and continue-as-new. Defaults to unlimited. + */ + private final java.time.Duration executionTimeout; + + /** Timeout of a single workflow run. Defaults to the workflow execution timeout. */ + private final java.time.Duration runTimeout; + + /** Timeout of a single workflow task. Defaults to 10 seconds. */ + private final java.time.Duration taskTimeout; + + /** Behavior when a closed workflow with the same ID exists. Default is allow-duplicate. */ + private final io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy; + + /** + * Behavior when a workflow is currently running with the same ID. Set to use-existing for + * idempotent deduplication on workflow ID. Cannot be set if id-reuse-policy is + * terminate-if-running. Defaults to use-existing. + */ + private final io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy; + + /** Retry policy for the workflow. */ + private final io.temporal.common.RetryOptions retryPolicy; + + /** Cron schedule for recurring workflow executions. See https://docs.temporal.io/cron-job. */ + private final String cronSchedule; + + /** Memo for the workflow. */ + private final java.util.Map memo; + + /** Typed search attributes for the workflow. */ + private final io.temporal.common.SearchAttributes searchAttributes; + + /** Priority of the workflow execution. */ + private final io.temporal.common.Priority priority; + + /** Override for workflow versioning behavior. */ + private final io.temporal.common.VersioningOverride versioningOverride; + + /** Amount of time to wait before starting the workflow. This does not work with cron-schedule. */ + private final java.time.Duration startDelay; + + /** + * Single-line fixed summary for the workflow execution that may appear in UI and CLI. This can be + * in single-line Temporal Markdown format. + */ + private final String staticSummary; + + /** + * General fixed details for the workflow execution that may appear in UI and CLI. This can be in + * Temporal Markdown format and can span multiple lines. This value is fixed on the workflow + * execution and cannot be updated. + */ + private final String staticDetails; + + public static SignalWithStartWorkflowOptions getDefaultInstance() { + return SignalWithStartWorkflowOptions.newBuilder().build(); + } + + private SignalWithStartWorkflowOptions( + java.util.List args, + java.util.List signalArgs, + java.time.Duration executionTimeout, + java.time.Duration runTimeout, + java.time.Duration taskTimeout, + io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy, + io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy, + io.temporal.common.RetryOptions retryPolicy, + String cronSchedule, + java.util.Map memo, + io.temporal.common.SearchAttributes searchAttributes, + io.temporal.common.Priority priority, + io.temporal.common.VersioningOverride versioningOverride, + java.time.Duration startDelay, + String staticSummary, + String staticDetails) { + this.args = args; + this.signalArgs = signalArgs; + this.executionTimeout = executionTimeout; + this.runTimeout = runTimeout; + this.taskTimeout = taskTimeout; + this.idReusePolicy = idReusePolicy; + this.idConflictPolicy = idConflictPolicy; + this.retryPolicy = retryPolicy; + this.cronSchedule = cronSchedule; + this.memo = memo; + this.searchAttributes = searchAttributes; + this.priority = priority; + this.versioningOverride = versioningOverride; + this.startDelay = startDelay; + this.staticSummary = staticSummary; + this.staticDetails = staticDetails; + } + + public java.util.List getArgs() { + return args; + } + + public java.util.List getSignalArgs() { + return signalArgs; + } + + public java.time.Duration getExecutionTimeout() { + return executionTimeout; + } + + public java.time.Duration getRunTimeout() { + return runTimeout; + } + + public java.time.Duration getTaskTimeout() { + return taskTimeout; + } + + public io.temporal.api.enums.v1.WorkflowIdReusePolicy getIdReusePolicy() { + return idReusePolicy; + } + + public io.temporal.api.enums.v1.WorkflowIdConflictPolicy getIdConflictPolicy() { + return idConflictPolicy; + } + + public io.temporal.common.RetryOptions getRetryPolicy() { + return retryPolicy; + } + + public String getCronSchedule() { + return cronSchedule; + } + + public java.util.Map getMemo() { + return memo; + } + + public io.temporal.common.SearchAttributes getSearchAttributes() { + return searchAttributes; + } + + public io.temporal.common.Priority getPriority() { + return priority; + } + + public io.temporal.common.VersioningOverride getVersioningOverride() { + return versioningOverride; + } + + public java.time.Duration getStartDelay() { + return startDelay; + } + + public String getStaticSummary() { + return staticSummary; + } + + public String getStaticDetails() { + return staticDetails; + } + + public Builder toBuilder() { + return newBuilder(this); + } + + public static Builder newBuilder(SignalWithStartWorkflowOptions value) { + return new Builder(value); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private Builder() {} + + private Builder(SignalWithStartWorkflowOptions value) { + if (value == null) return; + this.args = value.args; + this.signalArgs = value.signalArgs; + this.executionTimeout = value.executionTimeout; + this.runTimeout = value.runTimeout; + this.taskTimeout = value.taskTimeout; + this.idReusePolicy = value.idReusePolicy; + this.idConflictPolicy = value.idConflictPolicy; + this.retryPolicy = value.retryPolicy; + this.cronSchedule = value.cronSchedule; + this.memo = value.memo; + this.searchAttributes = value.searchAttributes; + this.priority = value.priority; + this.versioningOverride = value.versioningOverride; + this.startDelay = value.startDelay; + this.staticSummary = value.staticSummary; + this.staticDetails = value.staticDetails; + } + + private java.util.List args = null; + + public Builder setArgs(java.util.List value) { + this.args = value; + return this; + } + + public Builder setArgs(Object... values) { + this.args = values == null ? null : java.util.Arrays.asList(values); + return this; + } + + private java.util.List signalArgs = null; + + public Builder setSignalArgs(java.util.List value) { + this.signalArgs = value; + return this; + } + + public Builder setSignalArgs(Object... values) { + this.signalArgs = values == null ? null : java.util.Arrays.asList(values); + return this; + } + + private java.time.Duration executionTimeout = null; + + public Builder setExecutionTimeout(java.time.Duration value) { + this.executionTimeout = value; + return this; + } + + private java.time.Duration runTimeout = null; + + public Builder setRunTimeout(java.time.Duration value) { + this.runTimeout = value; + return this; + } + + private java.time.Duration taskTimeout = null; + + public Builder setTaskTimeout(java.time.Duration value) { + this.taskTimeout = value; + return this; + } + + private io.temporal.api.enums.v1.WorkflowIdReusePolicy idReusePolicy = + io.temporal.api.enums.v1.WorkflowIdReusePolicy.forNumber(1); + + public Builder setIdReusePolicy(io.temporal.api.enums.v1.WorkflowIdReusePolicy value) { + this.idReusePolicy = value; + return this; + } + + private io.temporal.api.enums.v1.WorkflowIdConflictPolicy idConflictPolicy = null; + + public Builder setIdConflictPolicy(io.temporal.api.enums.v1.WorkflowIdConflictPolicy value) { + this.idConflictPolicy = value; + return this; + } + + private io.temporal.common.RetryOptions retryPolicy = null; + + public Builder setRetryPolicy(io.temporal.common.RetryOptions value) { + this.retryPolicy = value; + return this; + } + + private String cronSchedule = null; + + public Builder setCronSchedule(String value) { + this.cronSchedule = value; + return this; + } + + private java.util.Map memo = null; + + public Builder setMemo(java.util.Map value) { + this.memo = value; + return this; + } + + private io.temporal.common.SearchAttributes searchAttributes = null; + + public Builder setSearchAttributes(io.temporal.common.SearchAttributes value) { + this.searchAttributes = value; + return this; + } + + private io.temporal.common.Priority priority = null; + + public Builder setPriority(io.temporal.common.Priority value) { + this.priority = value; + return this; + } + + private io.temporal.common.VersioningOverride versioningOverride = null; + + public Builder setVersioningOverride(io.temporal.common.VersioningOverride value) { + this.versioningOverride = value; + return this; + } + + private java.time.Duration startDelay = null; + + public Builder setStartDelay(java.time.Duration value) { + this.startDelay = value; + return this; + } + + private String staticSummary = null; + + public Builder setStaticSummary(String value) { + this.staticSummary = value; + return this; + } + + private String staticDetails = null; + + public Builder setStaticDetails(String value) { + this.staticDetails = value; + return this; + } + + public SignalWithStartWorkflowOptions build() { + return new SignalWithStartWorkflowOptions( + args, + signalArgs, + executionTimeout, + runTimeout, + taskTimeout, + idReusePolicy, + idConflictPolicy, + retryPolicy, + cronSchedule, + memo, + searchAttributes, + priority, + versioningOverride, + startDelay, + staticSummary, + staticDetails); + } + } +} diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java index e1bb6ed755..daf7a67246 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowRequest.java @@ -401,7 +401,7 @@ public Builder setHeaders(java.util.Map, /// @nexus.doc "General fixed details for the workflow execution that may appear in UI and CLI. This can be in Temporal Markdown format and can span multiple lines. This value is fixed on the workflow execution and cannot be updated." /// @nexus.proto-field "details" - /// @nexus.flattened-type python="str" typescript="string" dotnet="string" go="string" + /// @nexus.flattened-type java="String" python="str" typescript="string" dotnet="string" go="string" static-details: option, } } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java index d03bb45a9c..8355947eec 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -43,8 +43,23 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { request.getNamespace()); assertEquals("notify", request.getSignal()); assertEquals("queue", request.getTaskQueue()); - assertEquals("input", request.getArgs().get(0)); - assertEquals("signal", request.getSignalArgs().get(0)); + assertEquals( + io.temporal.api.enums.v1.WorkflowIdReusePolicy + .WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE, + request.getIdReusePolicy()); + if (request.getId().equals("defaults")) { + assertNull(request.getArgs()); + assertNull(request.getSignalArgs()); + } else { + assertEquals("input", request.getArgs().get(0)); + assertEquals("signal", request.getSignalArgs().get(0)); + assertEquals( + "summary", + request.getUserMetadata().getStaticSummary()); + assertEquals( + java.time.Duration.ofMinutes(3), + request.getRunTimeout()); + } return new ExecuteNexusOperationOutput<>( Workflow.newPromise( SignalWithStartWorkflowResponse.newBuilder() @@ -62,7 +77,8 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { @Test public void generatedWorkflowMethodsReturnExternalStubs() { - assertEquals("sync:run,async:run", rule.newWorkflowStubTimeoutOptions(Caller.class).run()); + assertEquals( + "sync:run,async:run,defaults:run", rule.newWorkflowStubTimeoutOptions(Caller.class).run()); } @WorkflowInterface @@ -74,27 +90,37 @@ public interface Caller { public static class CallerImpl implements Caller { @Override public String run() { - SignalWithStartWorkflowRequest request = - SignalWithStartWorkflowRequest.newBuilder() - .setWorkflow("Target") - .setSignal("notify") - .setId("sync") - .setTaskQueue("queue") - .setArgs(java.util.Collections.singletonList("input")) - .setSignalArgs(java.util.Collections.singletonList("signal")) + SignalWithStartWorkflowOptions options = + SignalWithStartWorkflowOptions.newBuilder() + .setArgs("input") + .setSignalArgs("signal") + .setStaticSummary("summary") + .setRunTimeout(java.time.Duration.ofMinutes(3)) .build(); - ExternalWorkflowStub sync = Workflow.signalWithStartWorkflow(request); + ExternalWorkflowStub sync = + Workflow.signalWithStartWorkflow("Target", "sync", "queue", "notify", options); ExternalWorkflowStub async = Async.function( - Workflow::signalWithStartWorkflow, request.toBuilder().setId("async").build()) + Workflow::signalWithStartWorkflow, + "Target", + "async", + "queue", + "notify", + options.toBuilder().build()) .get(); + ExternalWorkflowStub defaults = + Workflow.signalWithStartWorkflow("Target", "defaults", "queue", "notify"); return sync.getExecution().getWorkflowId() + ":" + sync.getExecution().getRunId() + "," + async.getExecution().getWorkflowId() + ":" - + async.getExecution().getRunId(); + + async.getExecution().getRunId() + + "," + + defaults.getExecution().getWorkflowId() + + ":" + + defaults.getExecution().getRunId(); } } } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java index ec54c2e571..86c9dabb9d 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -74,25 +74,24 @@ public static class CallerImpl implements Caller { @Override public String run() { String id = Workflow.getInfo().getWorkflowId() + "-target"; - SignalWithStartWorkflowRequest request = - SignalWithStartWorkflowRequest.newBuilder() - .setWorkflow("SystemSignalTarget") - .setSignal("notifySignal") - .setId(id) - .setTaskQueue(Workflow.getInfo().getTaskQueue()) + SignalWithStartWorkflowOptions options = + SignalWithStartWorkflowOptions.newBuilder() .setIdConflictPolicy( WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) - .setArgs(java.util.Collections.singletonList("start")) - .setSignalArgs(java.util.Collections.singletonList("first")) + .setArgs("start") + .setSignalArgs("first") .build(); - ExternalWorkflowStub external = Workflow.signalWithStartWorkflow(request); + ExternalWorkflowStub external = + Workflow.signalWithStartWorkflow( + "SystemSignalTarget", id, Workflow.getInfo().getTaskQueue(), "notifySignal", options); assertEquals(id, external.getExecution().getWorkflowId()); Async.function( Workflow::signalWithStartWorkflow, - request.toBuilder() - .setArgs(java.util.Collections.singletonList("ignored")) - .setSignalArgs(java.util.Collections.singletonList("second")) - .build()) + "SystemSignalTarget", + id, + Workflow.getInfo().getTaskQueue(), + "notifySignal", + options.toBuilder().setArgs("ignored").setSignalArgs("second").build()) .get(); return id; } From eb6b421e3766eceef6a983e3df3cf278428428dc Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Tue, 20 Oct 2026 11:31:18 -0700 Subject: [PATCH 12/17] Support typed workflow and signal callbacks in generated APIs --- CHANGELOG.md | 1 + .../temporal/workflow/WorkflowOperations.java | 90 ++++++++++++++ .../nexus/system/TemporalModelConverters.java | 88 ++++++++++++++ temporal-sdk/src/main/nexus/README.md | 7 +- .../src/main/nexus/SIGNAL_WITH_START.md | 20 +++ .../nexus/deps/nexus-temporal-types/model.wit | 2 + .../TypedWorkflowMethodCaptureTest.java | 115 ++++++++++++++++++ .../nexus/SignalWithStartWorkflowTest.java | 87 ++++++++++++- .../SystemSignalWithStartIntegrationTest.java | 9 +- 9 files changed, 409 insertions(+), 10 deletions(-) create mode 100644 temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fcf2c5dbd..4de1eeae42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ to docs, or any other relevant information. ### Added - Workflows can signal with start through the system workflow service using generated `Workflow.signalWithStartWorkflow(workflowType, workflowId, taskQueue, signalName, options)` API. + A typed overload accepts a workflow interface and workflow/signal callbacks with checked arguments. Request builders and operations are generated into `io.temporal.workflow`. System Nexus envelopes preserve destination workflow serialization context for nested payloads, codecs, and external payload storage. Requires a server supporting the system workflow service. diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java index 5918747c14..f70c582114 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java @@ -58,6 +58,96 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( return executeSignalWithStartWorkflow(request); } + /** + * Signal a workflow, starting it first if needed. + * + *

Each callback must invoke exactly one method on its receiver. Method names and arguments are + * captured without executing the call. Supply callback arguments through the callback, not + * options. The callback return value is discarded. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + Class workflowInterface, + io.temporal.workflow.Functions.Proc1 workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal) { + return signalWithStartWorkflow( + workflowInterface, + workflow, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Each callback must invoke exactly one method on its receiver. Method names and arguments are + * captured without executing the call. Supply callback arguments through the callback, not + * options. The callback return value is discarded. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + Class workflowInterface, + io.temporal.workflow.Functions.Proc1 workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflowInterface, + workflow, + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + workflowInterface, + signal, + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the typed callback, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the typed callback, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + static io.temporal.workflow.ExternalWorkflowStub executeSignalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowRequest request) { io.temporal.workflow.SignalWithStartWorkflowResponse result = diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java index 57825ebcef..9bc687a49d 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -5,13 +5,22 @@ import io.temporal.common.RetryOptions; import io.temporal.common.VersioningOverride; import io.temporal.common.converter.DataConverter; +import io.temporal.common.metadata.POJOWorkflowInterfaceMetadata; +import io.temporal.common.metadata.POJOWorkflowMethodMetadata; +import io.temporal.common.metadata.WorkflowMethodType; import io.temporal.internal.common.*; import io.temporal.payload.context.WorkflowSerializationContext; +import io.temporal.workflow.Functions; import io.temporal.workflow.SignalWithStartWorkflowRequest; import io.temporal.workflow.Workflow; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.time.Duration; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; +import java.util.function.BiConsumer; /** SDK-owned model conversion hooks used by the generated system Nexus bindings. */ public final class TemporalModelConverters { @@ -26,6 +35,85 @@ public static String workflowNamespace() { return Workflow.getInfo().getNamespace(); } + /** Captures one typed workflow invocation without starting a child workflow. */ + public static void captureWorkflowCall( + Class workflowInterface, Functions.Proc1 call, BiConsumer result) { + captureCall(workflowInterface, call, WorkflowMethodType.WORKFLOW, result); + } + + /** Captures one typed signal invocation without sending a signal. */ + public static void captureSignalCall( + Class workflowInterface, Functions.Proc1 call, BiConsumer result) { + captureCall(workflowInterface, call, WorkflowMethodType.SIGNAL, result); + } + + private static void captureCall( + Class workflowInterface, + Functions.Proc1 call, + WorkflowMethodType expected, + BiConsumer result) { + Objects.requireNonNull(call, "call"); + MethodCapture capture = new MethodCapture(workflowInterface, expected); + T receiver = + workflowInterface.cast( + Proxy.newProxyInstance( + workflowInterface.getClassLoader(), new Class[] {workflowInterface}, capture)); + try { + call.apply(receiver); + } finally { + capture.active = false; + } + if (capture.invocations != 1 || capture.name == null) { + throw new IllegalArgumentException( + "Callback must invoke exactly one " + expected + " method"); + } + result.accept(capture.name, capture.arguments); + } + + private static final class MethodCapture implements InvocationHandler { + private final POJOWorkflowInterfaceMetadata metadata; + private final WorkflowMethodType expected; + private boolean active = true; + private int invocations; + private String name; + private Object[] arguments; + + private MethodCapture(Class workflowInterface, WorkflowMethodType expected) { + this.metadata = POJOWorkflowInterfaceMetadata.newInstance(workflowInterface); + this.expected = expected; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + if (method.getDeclaringClass() == Object.class) { + switch (method.getName()) { + case "toString": + return "WorkflowMethodCapture{" + metadata.getInterfaceClass().getName() + "}"; + case "hashCode": + return System.identityHashCode(proxy); + case "equals": + return proxy == args[0]; + } + } + if (!active) { + throw new IllegalStateException( + "Captured workflow receiver cannot be used outside its callback"); + } + if (++invocations != 1) { + throw new IllegalArgumentException( + "Callback must invoke exactly one " + expected + " method"); + } + POJOWorkflowMethodMetadata methodMetadata = metadata.getMethodMetadata(method); + if (methodMetadata.getType() != expected) { + throw new IllegalArgumentException( + "Expected a " + expected + " method, got " + methodMetadata.getType()); + } + name = methodMetadata.getName(); + arguments = args == null ? new Object[0] : args.clone(); + return InternalUtils.getValueOrDefault(null, method.getReturnType()); + } + } + public static WorkflowSerializationContext signalWithStartWorkflowSerializationContext( SignalWithStartWorkflowRequest request) { return new WorkflowSerializationContext(request.getNamespace(), request.getId()); diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index 26fea40190..e4ad36b117 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -22,8 +22,11 @@ The generator uses `--package-name io.temporal.workflow` and the WIT annotation `@nexus.operations-class java="WorkflowOperations"`. `Workflow` extends this generated base once; additional operations require no handwritten facade methods. Generated operations take required fields as parameters and optional fields in -generated options builders, all available from the workflow package. The manifest derives -from operation input/output protobuf transfer types. The service client's Java +generated options builders, all available from the workflow package. +Typed overloads use workflow interfaces and invocation callbacks. SDK-owned +call-extractor hooks resolve annotated workflow/signal names and arguments +without executing commands; the generated wrapper constructs the request. +The manifest derives from operation input/output protobuf transfer types. The service client's Java payload visitor generator consumes it, including payload-free response roots, without depending on compiled SDK classes. diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md index 91c74cbba8..8f937fd7ab 100644 --- a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -25,6 +25,26 @@ stub supports further signals and cancellation. Use `Async.function(Workflow::signalWithStartWorkflow, workflowType, workflowId, taskQueue, signalName, options)` for a promise. +The typed overload checks workflow and signal arguments against their interface: + +```java +ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( + TargetWorkflow.class, w -> w.run(input), "target", "target-queue", + w -> w.notifySignal(signal), + SignalWithStartWorkflowOptions.newBuilder().setRunTimeout(timeout).build()); +``` + +Each callback must invoke exactly one method on its receiver: a `@WorkflowMethod` +for the workflow callback and a `@SignalMethod` for the signal callback. Calls are +captured without starting a child or sending a signal, and annotation names and +inherited methods follow the existing SDK metadata rules. Method references such +as `TargetWorkflow::run` work for methods without arguments; use a lambda to bind +arguments. The workflow return value is discarded. The receiver is valid only +inside its callback. Typed calls take all workflow/signal arguments from these +callbacks and reject `setArgs` or `setSignalArgs` in options. Both typed and +name-based forms return an external stub and support `Async.function` and the +overload omitting options. + `Workflow` inherits generated operations from `WorkflowOperations`. New WIT operations become available after regeneration, without adding handwritten options, capture proxies, stubs, or facade methods. The output transform, request diff --git a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit index 43f5da95be..68c117a879 100644 --- a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit +++ b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit @@ -91,6 +91,7 @@ interface model { /// go-name-extractor="WorkflowFunctionName" /// dotnet-name-extractor="TemporalFunctionNames.WorkflowName" /// dotnet-call-extractor="TemporalFunctionNames.ExtractCall" + /// java-call-extractor="captureWorkflowCall" /// @nexus.add-rpc-compatible-with "workflow-type" type workflow-function = placeholder; @@ -104,6 +105,7 @@ interface model { /// typescript-name-extractor="signalFunctionName" /// dotnet-name-extractor="TemporalFunctionNames.SignalName" /// dotnet-call-extractor="TemporalFunctionNames.ExtractCall" + /// java-call-extractor="captureSignalCall" /// typescript-value-type="common.SignalDefinition" /// typescript-args-type="Value extends common.SignalDefinition ? Args : never" /// typescript-import="@temporalio/common" diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java new file mode 100644 index 0000000000..3cb289c4f1 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java @@ -0,0 +1,115 @@ +package io.temporal.internal.nexus.system; + +import static org.junit.Assert.*; + +import io.temporal.workflow.*; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.Test; + +public class TypedWorkflowMethodCaptureTest { + public interface Base { + @SignalMethod(name = "custom-signal") + void signal(String value, int number); + } + + @WorkflowInterface + public interface Target extends Base { + @WorkflowMethod(name = "custom-workflow") + int start(String value); + + @QueryMethod + String query(); + + @UpdateMethod + String update(); + } + + @Test + public void usesAnnotatedNamesAndTypedArgumentsWithoutExecutingCommands() { + TemporalModelConverters.captureWorkflowCall( + Target.class, + w -> assertEquals(0, w.start("input")), + (name, args) -> { + assertEquals("custom-workflow", name); + assertArrayEquals(new Object[] {"input"}, args); + }); + TemporalModelConverters.captureSignalCall( + Target.class, + w -> w.signal("value", 42), + (name, args) -> { + assertEquals("custom-signal", name); + assertArrayEquals(new Object[] {"value", 42}, args); + }); + } + + @Test + public void rejectsMissingMultipleAndWrongKindOfCalls() { + assertThrows( + IllegalArgumentException.class, + () -> + TemporalModelConverters.captureWorkflowCall( + Target.class, w -> {}, (name, args) -> fail())); + assertThrows( + IllegalArgumentException.class, + () -> + TemporalModelConverters.captureWorkflowCall( + Target.class, + w -> { + w.start("first"); + w.start("second"); + }, + (name, args) -> fail())); + assertThrows( + IllegalArgumentException.class, + () -> + TemporalModelConverters.captureWorkflowCall( + Target.class, w -> w.signal("signal", 1), (name, args) -> fail())); + assertThrows( + IllegalArgumentException.class, + () -> + TemporalModelConverters.captureSignalCall( + Target.class, w -> w.start("input"), (name, args) -> fail())); + assertThrows( + IllegalArgumentException.class, + () -> + TemporalModelConverters.captureSignalCall( + Target.class, Target::query, (name, args) -> fail())); + assertThrows( + IllegalArgumentException.class, + () -> + TemporalModelConverters.captureSignalCall( + Target.class, Target::update, (name, args) -> fail())); + } + + @Test + public void receiversExpireAfterSuccessOrFailureAndCapturesRemainIndependent() { + AtomicReference receiver = new AtomicReference<>(); + TemporalModelConverters.captureWorkflowCall( + Target.class, + w -> { + receiver.set(w); + assertNotNull(w.toString()); + w.start("input"); + }, + (name, args) -> {}); + assertThrows(IllegalStateException.class, () -> receiver.get().start("escaped")); + RuntimeException failure = new RuntimeException("callback failed"); + assertSame( + failure, + assertThrows( + RuntimeException.class, + () -> + TemporalModelConverters.captureWorkflowCall( + Target.class, + w -> { + receiver.set(w); + throw failure; + }, + (name, args) -> fail()))); + assertThrows(IllegalStateException.class, () -> receiver.get().signal("escaped", 1)); + TemporalModelConverters.captureWorkflowCall( + Target.class, + w -> w.start("next"), + (name, args) -> assertArrayEquals(new Object[] {"next"}, args)); + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java index 8355947eec..caa0d34436 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -47,9 +47,14 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { io.temporal.api.enums.v1.WorkflowIdReusePolicy .WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE, request.getIdReusePolicy()); - if (request.getId().equals("defaults")) { - assertNull(request.getArgs()); - assertNull(request.getSignalArgs()); + if (request.getId().contains("defaults")) { + if (request.getId().equals("defaults")) { + assertNull(request.getArgs()); + assertNull(request.getSignalArgs()); + } else { + assertTrue(request.getArgs().isEmpty()); + assertTrue(request.getSignalArgs().isEmpty()); + } } else { assertEquals("input", request.getArgs().get(0)); assertEquals("signal", request.getSignalArgs().get(0)); @@ -78,7 +83,26 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { @Test public void generatedWorkflowMethodsReturnExternalStubs() { assertEquals( - "sync:run,async:run,defaults:run", rule.newWorkflowStubTimeoutOptions(Caller.class).run()); + "sync:run,async:run,defaults:run,typed:run,typed-async:run,typed-defaults:run", + rule.newWorkflowStubTimeoutOptions(Caller.class).run()); + } + + @WorkflowInterface + public interface TypedTarget { + @WorkflowMethod(name = "Target") + int start(String input); + + @SignalMethod(name = "notify") + void signalValue(String value); + } + + @WorkflowInterface + public interface EmptyTarget { + @WorkflowMethod(name = "Target") + void start(); + + @SignalMethod(name = "notify") + void signalValue(); } @WorkflowInterface @@ -110,6 +134,47 @@ public String run() { .get(); ExternalWorkflowStub defaults = Workflow.signalWithStartWorkflow("Target", "defaults", "queue", "notify"); + SignalWithStartWorkflowOptions typedOptions = + SignalWithStartWorkflowOptions.newBuilder() + .setStaticSummary("summary") + .setRunTimeout(java.time.Duration.ofMinutes(3)) + .build(); + ExternalWorkflowStub typed = + Workflow.signalWithStartWorkflow( + TypedTarget.class, + w -> w.start("input"), + "typed", + "queue", + w -> w.signalValue("signal"), + typedOptions); + ExternalWorkflowStub typedAsync = + Async.function( + () -> + Workflow.signalWithStartWorkflow( + TypedTarget.class, + w -> w.start("input"), + "typed-async", + "queue", + w -> w.signalValue("signal"), + typedOptions)) + .get(); + ExternalWorkflowStub typedDefaults = + Workflow.signalWithStartWorkflow( + EmptyTarget.class, + EmptyTarget::start, + "typed-defaults", + "queue", + EmptyTarget::signalValue); + assertThrows( + IllegalArgumentException.class, + () -> + Workflow.signalWithStartWorkflow( + TypedTarget.class, + w -> w.start("input"), + "invalid", + "queue", + w -> w.signalValue("signal"), + options)); return sync.getExecution().getWorkflowId() + ":" + sync.getExecution().getRunId() @@ -120,7 +185,19 @@ public String run() { + "," + defaults.getExecution().getWorkflowId() + ":" - + defaults.getExecution().getRunId(); + + defaults.getExecution().getRunId() + + "," + + typed.getExecution().getWorkflowId() + + ":" + + typed.getExecution().getRunId() + + "," + + typedAsync.getExecution().getWorkflowId() + + ":" + + typedAsync.getExecution().getRunId() + + "," + + typedDefaults.getExecution().getWorkflowId() + + ":" + + typedDefaults.getExecution().getRunId(); } } } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java index 86c9dabb9d..863a105588 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -78,12 +78,15 @@ public String run() { SignalWithStartWorkflowOptions.newBuilder() .setIdConflictPolicy( WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) - .setArgs("start") - .setSignalArgs("first") .build(); ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( - "SystemSignalTarget", id, Workflow.getInfo().getTaskQueue(), "notifySignal", options); + Target.class, + w -> w.run("start"), + id, + Workflow.getInfo().getTaskQueue(), + w -> w.notifySignal("first"), + options); assertEquals(id, external.getExecution().getWorkflowId()); Async.function( Workflow::signalWithStartWorkflow, From b0d11e0dc41aebb4af1c7deaf47c6deaaca431b1 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Wed, 21 Oct 2026 09:15:54 -0700 Subject: [PATCH 13/17] Probe external stubs for direct bound-method workflow APIs --- CHANGELOG.md | 2 +- .../temporal/workflow/WorkflowOperations.java | 2858 ++++++++++++++++- .../nexus/system/TemporalModelConverters.java | 90 +- .../ExternalWorkflowInvocationHandler.java | 123 +- temporal-sdk/src/main/nexus/README.md | 6 +- .../src/main/nexus/SIGNAL_WITH_START.md | 34 +- .../nexus/deps/nexus-temporal-types/model.wit | 2 +- .../TypedWorkflowMethodCaptureTest.java | 211 +- .../nexus/SignalWithStartWorkflowTest.java | 78 +- .../SystemSignalWithStartIntegrationTest.java | 8 +- 10 files changed, 3223 insertions(+), 189 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4de1eeae42..23357b121a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ to docs, or any other relevant information. ### Added - Workflows can signal with start through the system workflow service using generated `Workflow.signalWithStartWorkflow(workflowType, workflowId, taskQueue, signalName, options)` API. - A typed overload accepts a workflow interface and workflow/signal callbacks with checked arguments. + Typed overloads accept bound workflow/signal methods followed directly by checked arguments. Request builders and operations are generated into `io.temporal.workflow`. System Nexus envelopes preserve destination workflow serialization context for nested payloads, codecs, and external payload storage. Requires a server supporting the system workflow service. diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java index f70c582114..036bea5b63 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java @@ -61,46 +61,2866 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( /** * Signal a workflow, starting it first if needed. * - *

Each callback must invoke exactly one method on its receiver. Method names and arguments are - * captured without executing the call. Supply callback arguments through the callback, not - * options. The callback return value is discarded. + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. */ - public static + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc workflow, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc1 workflow, + WorkflowArg1 workflowArg1, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc2 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func3< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func3< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func3< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func3< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc3 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc3 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc3 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc3 workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc4< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static < + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5, WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func5< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static < + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5, WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func5< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func5< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func5< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc5< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc5< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc5< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc5< + WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static < + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static < + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5, workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6, + id, + taskQueue, + signal, + signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Func6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6, + WorkflowResult> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5, workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(signalArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal) { + return signalWithStartWorkflow( + workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6, + id, + taskQueue, + signal, + io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static + io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( + io.temporal.workflow.Functions.Proc6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, + String id, + String taskQueue, + io.temporal.workflow.Functions.Proc signal, + io.temporal.workflow.SignalWithStartWorkflowOptions options) { + io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = + io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5, workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); + requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); + requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( + signal, + () -> signal.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setSignal(capturedName); + requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); + }); + if (options != null) { + if (options.getArgs() != null) + throw new IllegalArgumentException( + "args must be supplied through the bound call, not options"); + if (options.getSignalArgs() != null) + throw new IllegalArgumentException( + "signalArgs must be supplied through the bound call, not options"); + if (options.getExecutionTimeout() != null) + requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); + if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); + if (options.getTaskTimeout() != null) requestBuilder.setTaskTimeout(options.getTaskTimeout()); + if (options.getIdReusePolicy() != null) + requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); + if (options.getIdConflictPolicy() != null) + requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); + if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); + if (options.getCronSchedule() != null) + requestBuilder.setCronSchedule(options.getCronSchedule()); + if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); + if (options.getSearchAttributes() != null) + requestBuilder.setSearchAttributes(options.getSearchAttributes()); + if (options.getPriority() != null) requestBuilder.setPriority(options.getPriority()); + if (options.getVersioningOverride() != null) + requestBuilder.setVersioningOverride(options.getVersioningOverride()); + if (options.getStartDelay() != null) requestBuilder.setStartDelay(options.getStartDelay()); + if (options.getStaticSummary() != null) + requestBuilder.setStaticSummary(options.getStaticSummary()); + if (options.getStaticDetails() != null) + requestBuilder.setStaticDetails(options.getStaticDetails()); + } + io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); + return executeSignalWithStartWorkflow(request); + } + + /** + * Signal a workflow, starting it first if needed. + * + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. + */ + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( - Class workflowInterface, - io.temporal.workflow.Functions.Proc1 workflow, + io.temporal.workflow.Functions.Proc6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, String id, String taskQueue, - io.temporal.workflow.Functions.Proc1 signal) { + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1) { return signalWithStartWorkflow( - workflowInterface, workflow, + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6, id, taskQueue, signal, + signalArg1, io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); } /** * Signal a workflow, starting it first if needed. * - *

Each callback must invoke exactly one method on its receiver. Method names and arguments are - * captured without executing the call. Supply callback arguments through the callback, not - * options. The callback return value is discarded. + *

Pass bound method references followed by their arguments. SDK-owned call extractors probe + * these invocations. Supply invocation arguments as parameters, not in options. Other required + * fields remain explicit; automatic merging of probed options is not defined. */ - public static + public static < + SignalArg1, + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( - Class workflowInterface, - io.temporal.workflow.Functions.Proc1 workflow, + io.temporal.workflow.Functions.Proc6< + WorkflowArg1, + WorkflowArg2, + WorkflowArg3, + WorkflowArg4, + WorkflowArg5, + WorkflowArg6> + workflow, + WorkflowArg1 workflowArg1, + WorkflowArg2 workflowArg2, + WorkflowArg3 workflowArg3, + WorkflowArg4 workflowArg4, + WorkflowArg5 workflowArg5, + WorkflowArg6 workflowArg6, String id, String taskQueue, - io.temporal.workflow.Functions.Proc1 signal, + io.temporal.workflow.Functions.Proc1 signal, + SignalArg1 signalArg1, io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflowInterface, workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5, workflowArg6), (capturedName, capturedArguments) -> { requestBuilder.setWorkflow(capturedName); requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); @@ -108,8 +2928,8 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( - workflowInterface, signal, + () -> signal.apply(signalArg1), (capturedName, capturedArguments) -> { requestBuilder.setSignal(capturedName); requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); @@ -117,10 +2937,10 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options != null) { if (options.getArgs() != null) throw new IllegalArgumentException( - "args must be supplied through the typed callback, not options"); + "args must be supplied through the bound call, not options"); if (options.getSignalArgs() != null) throw new IllegalArgumentException( - "signalArgs must be supplied through the typed callback, not options"); + "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java index 9bc687a49d..8a6050be07 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -5,21 +5,16 @@ import io.temporal.common.RetryOptions; import io.temporal.common.VersioningOverride; import io.temporal.common.converter.DataConverter; -import io.temporal.common.metadata.POJOWorkflowInterfaceMetadata; -import io.temporal.common.metadata.POJOWorkflowMethodMetadata; import io.temporal.common.metadata.WorkflowMethodType; import io.temporal.internal.common.*; +import io.temporal.internal.sync.ExternalWorkflowInvocationHandler; import io.temporal.payload.context.WorkflowSerializationContext; import io.temporal.workflow.Functions; import io.temporal.workflow.SignalWithStartWorkflowRequest; import io.temporal.workflow.Workflow; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; import java.time.Duration; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Objects; import java.util.function.BiConsumer; /** SDK-owned model conversion hooks used by the generated system Nexus bindings. */ @@ -36,82 +31,19 @@ public static String workflowNamespace() { } /** Captures one typed workflow invocation without starting a child workflow. */ - public static void captureWorkflowCall( - Class workflowInterface, Functions.Proc1 call, BiConsumer result) { - captureCall(workflowInterface, call, WorkflowMethodType.WORKFLOW, result); + public static void captureWorkflowCall( + Object method, Functions.Proc invocation, BiConsumer result) { + ExternalWorkflowInvocationHandler.ProbeResult call = + ExternalWorkflowInvocationHandler.probe(method, invocation, WorkflowMethodType.WORKFLOW); + result.accept(call.getName(), call.getArguments()); } /** Captures one typed signal invocation without sending a signal. */ - public static void captureSignalCall( - Class workflowInterface, Functions.Proc1 call, BiConsumer result) { - captureCall(workflowInterface, call, WorkflowMethodType.SIGNAL, result); - } - - private static void captureCall( - Class workflowInterface, - Functions.Proc1 call, - WorkflowMethodType expected, - BiConsumer result) { - Objects.requireNonNull(call, "call"); - MethodCapture capture = new MethodCapture(workflowInterface, expected); - T receiver = - workflowInterface.cast( - Proxy.newProxyInstance( - workflowInterface.getClassLoader(), new Class[] {workflowInterface}, capture)); - try { - call.apply(receiver); - } finally { - capture.active = false; - } - if (capture.invocations != 1 || capture.name == null) { - throw new IllegalArgumentException( - "Callback must invoke exactly one " + expected + " method"); - } - result.accept(capture.name, capture.arguments); - } - - private static final class MethodCapture implements InvocationHandler { - private final POJOWorkflowInterfaceMetadata metadata; - private final WorkflowMethodType expected; - private boolean active = true; - private int invocations; - private String name; - private Object[] arguments; - - private MethodCapture(Class workflowInterface, WorkflowMethodType expected) { - this.metadata = POJOWorkflowInterfaceMetadata.newInstance(workflowInterface); - this.expected = expected; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) { - if (method.getDeclaringClass() == Object.class) { - switch (method.getName()) { - case "toString": - return "WorkflowMethodCapture{" + metadata.getInterfaceClass().getName() + "}"; - case "hashCode": - return System.identityHashCode(proxy); - case "equals": - return proxy == args[0]; - } - } - if (!active) { - throw new IllegalStateException( - "Captured workflow receiver cannot be used outside its callback"); - } - if (++invocations != 1) { - throw new IllegalArgumentException( - "Callback must invoke exactly one " + expected + " method"); - } - POJOWorkflowMethodMetadata methodMetadata = metadata.getMethodMetadata(method); - if (methodMetadata.getType() != expected) { - throw new IllegalArgumentException( - "Expected a " + expected + " method, got " + methodMetadata.getType()); - } - name = methodMetadata.getName(); - arguments = args == null ? new Object[0] : args.clone(); - return InternalUtils.getValueOrDefault(null, method.getReturnType()); - } + public static void captureSignalCall( + Object method, Functions.Proc invocation, BiConsumer result) { + ExternalWorkflowInvocationHandler.ProbeResult call = + ExternalWorkflowInvocationHandler.probe(method, invocation, WorkflowMethodType.SIGNAL); + result.accept(call.getName(), call.getArguments()); } public static WorkflowSerializationContext signalWithStartWorkflowSerializationContext( diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java index 0f7def87ea..aef6ff3a48 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java @@ -1,16 +1,126 @@ package io.temporal.internal.sync; import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.CronSchedule; +import io.temporal.common.MethodRetry; +import io.temporal.common.RetryOptions; import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; import io.temporal.common.metadata.POJOWorkflowInterfaceMetadata; import io.temporal.common.metadata.POJOWorkflowMethodMetadata; +import io.temporal.common.metadata.WorkflowMethodType; +import io.temporal.internal.common.InternalUtils; +import io.temporal.internal.common.JavaLambdaUtils; import io.temporal.workflow.ExternalWorkflowStub; import io.temporal.workflow.Functions; +import java.lang.invoke.MethodHandleInfo; +import java.lang.invoke.SerializedLambda; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; +import java.util.Objects; -/** Dynamic implementation of a strongly typed child workflow interface. */ -class ExternalWorkflowInvocationHandler implements InvocationHandler { +/** Dynamic implementation of a strongly typed external workflow interface. */ +public class ExternalWorkflowInvocationHandler implements InvocationHandler { + + private static final ThreadLocal probeContext = new ThreadLocal<>(); + private static final ThreadLocal probeResult = new ThreadLocal<>(); + + /** Probes one invocation without starting a workflow or sending a signal. */ + public static ProbeResult probe( + Object method, Functions.Proc invocation, WorkflowMethodType expected) { + Objects.requireNonNull(invocation, "invocation"); + if (probeContext.get() != null) { + throw new IllegalStateException("Already probing an external workflow invocation"); + } + SerializedLambda reference = + JavaLambdaUtils.toSerializedLambda(Objects.requireNonNull(method, "method")); + Object target = JavaLambdaUtils.getTarget(reference); + if (reference == null + || reference.getImplMethodKind() != MethodHandleInfo.REF_invokeInterface + || target == null + || !Proxy.isProxyClass(target.getClass()) + || !(Proxy.getInvocationHandler(target) instanceof ExternalWorkflowInvocationHandler)) { + throw new IllegalArgumentException( + "Expected a bound method from Workflow.newExternalWorkflowStub"); + } + ProbeContext context = new ProbeContext(expected); + probeContext.set(context); + try { + invocation.apply(); + ProbeResult result = probeResult.get(); + if (context.invocations != 1 || result == null) { + throw new IllegalArgumentException( + "Expected exactly one external workflow " + expected + " invocation"); + } + return result; + } finally { + probeResult.remove(); + probeContext.remove(); + } + } + + private static final class ProbeContext { + private final WorkflowMethodType expected; + private int invocations; + + private ProbeContext(WorkflowMethodType expected) { + this.expected = Objects.requireNonNull(expected, "expected"); + } + } + + /** Metadata captured from a bound external workflow method. */ + public static final class ProbeResult { + private final ExternalWorkflowStub stub; + private final String name; + private final Object[] arguments; + private final Class resultClass; + private final Type resultType; + private final WorkflowOptions options; + + private ProbeResult( + ExternalWorkflowStub stub, POJOWorkflowMethodMetadata metadata, Object[] args) { + this.stub = stub; + this.name = metadata.getName(); + this.arguments = args == null ? new Object[0] : args.clone(); + Method method = metadata.getWorkflowMethod(); + this.resultClass = method.getReturnType(); + this.resultType = method.getGenericReturnType(); + MethodRetry retry = method.getAnnotation(MethodRetry.class); + CronSchedule cron = method.getAnnotation(CronSchedule.class); + this.options = + WorkflowOptions.newBuilder() + .setWorkflowId(stub.getExecution().getWorkflowId()) + .setRetryOptions(RetryOptions.merge(retry, null)) + .setCronSchedule(cron == null ? null : cron.value()) + .build(); + } + + public ExternalWorkflowStub getStub() { + return stub; + } + + public String getName() { + return name; + } + + public Object[] getArguments() { + return arguments.clone(); + } + + public Class getResultClass() { + return resultClass; + } + + public Type getResultType() { + return resultType; + } + + public WorkflowOptions getOptions() { + return options; + } + } private final ExternalWorkflowStub stub; private final POJOWorkflowInterfaceMetadata workflowMetadata; @@ -40,6 +150,15 @@ public Object invoke(Object proxy, Method method, Object[] args) { return stub; } POJOWorkflowMethodMetadata methodMetadata = workflowMetadata.getMethodMetadata(method); + ProbeContext context = probeContext.get(); + if (context != null) { + if (++context.invocations != 1 || methodMetadata.getType() != context.expected) { + throw new IllegalArgumentException( + "Expected exactly one external workflow " + context.expected + " invocation"); + } + probeResult.set(new ProbeResult(stub, methodMetadata, args)); + return InternalUtils.getValueOrDefault(null, method.getReturnType()); + } switch (methodMetadata.getType()) { case QUERY: throw new UnsupportedOperationException( diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index e4ad36b117..ebcb3dcb15 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -23,9 +23,13 @@ The generator uses `--package-name io.temporal.workflow` and the WIT annotation generated base once; additional operations require no handwritten facade methods. Generated operations take required fields as parameters and optional fields in generated options builders, all available from the workflow package. -Typed overloads use workflow interfaces and invocation callbacks. SDK-owned +Typed overloads take bound methods followed directly by arguments. SDK-owned call-extractor hooks resolve annotated workflow/signal names and arguments without executing commands; the generated wrapper constructs the request. +Primary callable arities zero through six and other callable arities zero or one +come from Java rendering policy and the IDL's primary marker. No operation names +or composite-operation roles are encoded in the generator. Probed options remain +available in the SDK; automatic merging awaits IDL mapping and precedence rules. The manifest derives from operation input/output protobuf transfer types. The service client's Java payload visitor generator consumes it, including payload-free response roots, without depending on compiled SDK classes. diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md index 8f937fd7ab..70360bb4bd 100644 --- a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -29,21 +29,31 @@ The typed overload checks workflow and signal arguments against their interface: ```java ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( - TargetWorkflow.class, w -> w.run(input), "target", "target-queue", - w -> w.notifySignal(signal), + target::run, input, "target", "target-queue", + target::notifySignal, signal, SignalWithStartWorkflowOptions.newBuilder().setRunTimeout(timeout).build()); ``` -Each callback must invoke exactly one method on its receiver: a `@WorkflowMethod` -for the workflow callback and a `@SignalMethod` for the signal callback. Calls are -captured without starting a child or sending a signal, and annotation names and -inherited methods follow the existing SDK metadata rules. Method references such -as `TargetWorkflow::run` work for methods without arguments; use a lambda to bind -arguments. The workflow return value is discarded. The receiver is valid only -inside its callback. Typed calls take all workflow/signal arguments from these -callbacks and reject `setArgs` or `setSignalArgs` in options. Both typed and -name-based forms return an external stub and support `Async.function` and the -overload omitting options. +Create `target` with `Workflow.newExternalWorkflowStub(TargetWorkflow.class, "target")`. +Pass bound workflow and signal methods followed directly by their arguments. +Typed overloads cover zero through six workflow arguments and zero or one signal +argument, including void workflow methods. Other arities use the name-based API. +The compiler checks arguments and retains generic workflow result information in +the functional interface. The operation itself returns an external stub, not the +workflow result. + +The existing external invocation handler probes method names, arguments, result +types, target execution, and annotation-derived retry/cron options using scoped +thread locals. It sends no commands while probing and restores normal invocation +behavior afterward, including on failure. Query/update methods and receiver +lambdas are rejected. Typed calls reject `setArgs` or `setSignalArgs` in options. +Both forms support `Async.function` and an overload omitting options. + +Workflow ID and task queue remain explicit. The IDL does not define how probed +options map to request fields, precedence between those options and explicit +options, or relationships between the workflow and signal references. Automatic +options merging and cross-reference constraints are deferred rather than +hardcoded in the generator. Explicit ID, task queue, and options govern this call. `Workflow` inherits generated operations from `WorkflowOperations`. New WIT operations become available after regeneration, without adding handwritten diff --git a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit index 68c117a879..56c7f6fc78 100644 --- a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit +++ b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit @@ -60,7 +60,7 @@ interface model { workflow-call: async func(callable-prefix: callable-prefix, args: payloads) -> workflow-result; /// Callable result annotation for signal functions. - /// @nexus.type python="None | collections.abc.Awaitable[None]" typescript="void" go="any" dotnet="void" + /// @nexus.type java="Void" python="None | collections.abc.Awaitable[None]" typescript="void" go="any" dotnet="void" type signal-result = placeholder; /// @nexus.function-args diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java index 3cb289c4f1..c1922b9041 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java @@ -1,9 +1,20 @@ package io.temporal.internal.nexus.system; import static org.junit.Assert.*; +import static org.mockito.Mockito.*; +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.common.CronSchedule; +import io.temporal.common.MethodRetry; +import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; +import io.temporal.common.metadata.WorkflowMethodType; +import io.temporal.internal.sync.ExternalWorkflowInvocationHandler; +import io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult; +import io.temporal.internal.sync.StubMarker; import io.temporal.workflow.*; -import java.util.concurrent.atomic.AtomicReference; +import java.lang.reflect.Proxy; +import java.util.List; +import java.util.concurrent.*; import org.junit.Test; public class TypedWorkflowMethodCaptureTest { @@ -15,6 +26,8 @@ public interface Base { @WorkflowInterface public interface Target extends Base { @WorkflowMethod(name = "custom-workflow") + @MethodRetry(maximumAttempts = 3) + @CronSchedule("0 * * * *") int start(String value); @QueryMethod @@ -24,92 +37,180 @@ public interface Target extends Base { String update(); } + @WorkflowInterface + public interface GenericTarget { + @WorkflowMethod + List start(); + } + + private final WorkflowOutboundCallsInterceptor outbound = + mock(WorkflowOutboundCallsInterceptor.class); + private final RuntimeException normalSignal = new IllegalStateException("normal signal path"); + + private T stub(Class type, String id) { + return type.cast( + Proxy.newProxyInstance( + type.getClassLoader(), + new Class[] {type, StubMarker.class}, + new ExternalWorkflowInvocationHandler( + type, + WorkflowExecution.newBuilder().setWorkflowId(id).build(), + outbound, + ignored -> { + throw normalSignal; + }))); + } + @Test - public void usesAnnotatedNamesAndTypedArgumentsWithoutExecutingCommands() { - TemporalModelConverters.captureWorkflowCall( - Target.class, - w -> assertEquals(0, w.start("input")), - (name, args) -> { - assertEquals("custom-workflow", name); - assertArrayEquals(new Object[] {"input"}, args); - }); - TemporalModelConverters.captureSignalCall( - Target.class, - w -> w.signal("value", 42), - (name, args) -> { - assertEquals("custom-signal", name); - assertArrayEquals(new Object[] {"value", 42}, args); - }); + public void probesNamesArgumentsOptionsAndReturnTypesWithoutCommands() { + Target target = stub(Target.class, "target"); + Functions.Func1 method = target::start; + ProbeResult call = + ExternalWorkflowInvocationHandler.probe( + method, + () -> assertEquals(0, (int) method.apply("input")), + WorkflowMethodType.WORKFLOW); + assertEquals("custom-workflow", call.getName()); + assertArrayEquals(new Object[] {"input"}, call.getArguments()); + assertEquals(int.class, call.getResultClass()); + assertEquals(int.class, call.getResultType()); + assertEquals("target", call.getOptions().getWorkflowId()); + assertEquals(3, call.getOptions().getRetryOptions().getMaximumAttempts()); + assertEquals("0 * * * *", call.getOptions().getCronSchedule()); + assertSame(ExternalWorkflowStub.fromTyped(target), call.getStub()); + call.getArguments()[0] = "changed"; + assertEquals("input", call.getArguments()[0]); + + Functions.Proc2 signal = target::signal; + ProbeResult signalCall = + ExternalWorkflowInvocationHandler.probe( + signal, () -> signal.apply("value", 42), WorkflowMethodType.SIGNAL); + assertEquals("custom-signal", signalCall.getName()); + assertArrayEquals(new Object[] {"value", 42}, signalCall.getArguments()); + GenericTarget generic = stub(GenericTarget.class, "generic"); + Functions.Func> start = generic::start; + ProbeResult genericCall = + ExternalWorkflowInvocationHandler.probe( + start, () -> start.apply(), WorkflowMethodType.WORKFLOW); + assertEquals("java.util.List", genericCall.getResultType().getTypeName()); + verifyNoInteractions(outbound); + assertThrows(IllegalStateException.class, () -> target.start("outside probe")); + assertSame( + normalSignal, assertThrows(RuntimeException.class, () -> target.signal("outside", 1))); } @Test - public void rejectsMissingMultipleAndWrongKindOfCalls() { + public void rejectsMissingRepeatedWrongKindAndNonBoundInvocations() { + Target target = stub(Target.class, "target"); + Functions.Func1 start = target::start; assertThrows( IllegalArgumentException.class, () -> - TemporalModelConverters.captureWorkflowCall( - Target.class, w -> {}, (name, args) -> fail())); + ExternalWorkflowInvocationHandler.probe(start, () -> {}, WorkflowMethodType.WORKFLOW)); assertThrows( IllegalArgumentException.class, () -> - TemporalModelConverters.captureWorkflowCall( - Target.class, - w -> { - w.start("first"); - w.start("second"); + ExternalWorkflowInvocationHandler.probe( + start, + () -> { + start.apply("first"); + start.apply("second"); }, - (name, args) -> fail())); + WorkflowMethodType.WORKFLOW)); assertThrows( IllegalArgumentException.class, () -> - TemporalModelConverters.captureWorkflowCall( - Target.class, w -> w.signal("signal", 1), (name, args) -> fail())); + ExternalWorkflowInvocationHandler.probe( + start, () -> start.apply("input"), WorkflowMethodType.SIGNAL)); + Functions.Proc2 signal = target::signal; assertThrows( IllegalArgumentException.class, () -> - TemporalModelConverters.captureSignalCall( - Target.class, w -> w.start("input"), (name, args) -> fail())); + ExternalWorkflowInvocationHandler.probe( + signal, () -> signal.apply("value", 1), WorkflowMethodType.WORKFLOW)); + Functions.Func query = target::query; + Functions.Func update = target::update; assertThrows( IllegalArgumentException.class, () -> - TemporalModelConverters.captureSignalCall( - Target.class, Target::query, (name, args) -> fail())); + ExternalWorkflowInvocationHandler.probe( + query, () -> query.apply(), WorkflowMethodType.SIGNAL)); assertThrows( IllegalArgumentException.class, () -> - TemporalModelConverters.captureSignalCall( - Target.class, Target::update, (name, args) -> fail())); + ExternalWorkflowInvocationHandler.probe( + update, () -> update.apply(), WorkflowMethodType.SIGNAL)); + Functions.Proc lambda = () -> target.start("input"); + assertThrows( + IllegalArgumentException.class, + () -> ExternalWorkflowInvocationHandler.probe(lambda, lambda, WorkflowMethodType.WORKFLOW)); + verifyNoInteractions(outbound); } @Test - public void receiversExpireAfterSuccessOrFailureAndCapturesRemainIndependent() { - AtomicReference receiver = new AtomicReference<>(); - TemporalModelConverters.captureWorkflowCall( - Target.class, - w -> { - receiver.set(w); - assertNotNull(w.toString()); - w.start("input"); - }, - (name, args) -> {}); - assertThrows(IllegalStateException.class, () -> receiver.get().start("escaped")); - RuntimeException failure = new RuntimeException("callback failed"); + public void restoresProbeStateAfterFailureAndRejectsNesting() { + Target target = stub(Target.class, "target"); + Functions.Func1 method = target::start; + RuntimeException failure = new RuntimeException("failed"); assertSame( failure, assertThrows( RuntimeException.class, () -> - TemporalModelConverters.captureWorkflowCall( - Target.class, - w -> { - receiver.set(w); + ExternalWorkflowInvocationHandler.probe( + method, + () -> { throw failure; }, - (name, args) -> fail()))); - assertThrows(IllegalStateException.class, () -> receiver.get().signal("escaped", 1)); - TemporalModelConverters.captureWorkflowCall( - Target.class, - w -> w.start("next"), - (name, args) -> assertArrayEquals(new Object[] {"next"}, args)); + WorkflowMethodType.WORKFLOW))); + ProbeResult result = + ExternalWorkflowInvocationHandler.probe( + method, + () -> { + assertThrows( + IllegalStateException.class, + () -> + ExternalWorkflowInvocationHandler.probe( + method, () -> method.apply("nested"), WorkflowMethodType.WORKFLOW)); + method.apply("outer"); + }, + WorkflowMethodType.WORKFLOW); + assertArrayEquals(new Object[] {"outer"}, result.getArguments()); + assertThrows(IllegalStateException.class, () -> target.start("outside probe")); + verifyNoInteractions(outbound); + } + + @Test + public void isolatesProbeResultsAcrossThreads() throws Exception { + Target first = stub(Target.class, "first"); + Target second = stub(Target.class, "second"); + CyclicBarrier barrier = new CyclicBarrier(2); + ExecutorService executor = Executors.newFixedThreadPool(2); + try { + Future a = executor.submit(() -> parallelProbe(first::start, "a", barrier)); + Future b = executor.submit(() -> parallelProbe(second::start, "b", barrier)); + assertEquals("first:a", a.get(10, TimeUnit.SECONDS)); + assertEquals("second:b", b.get(10, TimeUnit.SECONDS)); + } finally { + executor.shutdownNow(); + } + verifyNoInteractions(outbound); + } + + private String parallelProbe( + Functions.Func1 method, String value, CyclicBarrier barrier) { + ProbeResult result = + ExternalWorkflowInvocationHandler.probe( + method, + () -> { + try { + barrier.await(5, TimeUnit.SECONDS); + } catch (Exception e) { + throw new RuntimeException(e); + } + method.apply(value); + }, + WorkflowMethodType.WORKFLOW); + return result.getOptions().getWorkflowId() + ":" + result.getArguments()[0]; } } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java index caa0d34436..c4c55f1cfb 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -57,6 +57,17 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { } } else { assertEquals("input", request.getArgs().get(0)); + if (request.getId().equals("arity6")) { + assertEquals( + java.util.Arrays.asList( + "input", + 2, + 3L, + true, + java.util.Collections.singletonList("nested"), + java.util.Collections.singletonMap("key", 4)), + request.getArgs()); + } assertEquals("signal", request.getSignalArgs().get(0)); assertEquals( "summary", @@ -83,7 +94,7 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { @Test public void generatedWorkflowMethodsReturnExternalStubs() { assertEquals( - "sync:run,async:run,defaults:run,typed:run,typed-async:run,typed-defaults:run", + "sync:run,async:run,defaults:run,typed:run,typed-async:run,typed-defaults:run,arity6:run", rule.newWorkflowStubTimeoutOptions(Caller.class).run()); } @@ -105,6 +116,21 @@ public interface EmptyTarget { void signalValue(); } + @WorkflowInterface + public interface SixArgumentTarget { + @WorkflowMethod(name = "Target") + java.util.List start( + String first, + int second, + long third, + boolean fourth, + java.util.List fifth, + java.util.Map sixth); + + @SignalMethod(name = "notify") + void signalValue(String value); + } + @WorkflowInterface public interface Caller { @WorkflowMethod @@ -139,42 +165,58 @@ public String run() { .setStaticSummary("summary") .setRunTimeout(java.time.Duration.ofMinutes(3)) .build(); + TypedTarget target = Workflow.newExternalWorkflowStub(TypedTarget.class, "typed"); ExternalWorkflowStub typed = Workflow.signalWithStartWorkflow( - TypedTarget.class, - w -> w.start("input"), + target::start, + "input", "typed", "queue", - w -> w.signalValue("signal"), + target::signalValue, + "signal", typedOptions); ExternalWorkflowStub typedAsync = Async.function( () -> Workflow.signalWithStartWorkflow( - TypedTarget.class, - w -> w.start("input"), + target::start, + "input", "typed-async", "queue", - w -> w.signalValue("signal"), + target::signalValue, + "signal", typedOptions)) .get(); + EmptyTarget empty = Workflow.newExternalWorkflowStub(EmptyTarget.class, "typed-defaults"); ExternalWorkflowStub typedDefaults = Workflow.signalWithStartWorkflow( - EmptyTarget.class, - EmptyTarget::start, - "typed-defaults", - "queue", - EmptyTarget::signalValue); + empty::start, "typed-defaults", "queue", empty::signalValue); assertThrows( IllegalArgumentException.class, () -> Workflow.signalWithStartWorkflow( - TypedTarget.class, - w -> w.start("input"), + target::start, + "input", "invalid", "queue", - w -> w.signalValue("signal"), + target::signalValue, + "signal", options)); + SixArgumentTarget six = Workflow.newExternalWorkflowStub(SixArgumentTarget.class, "arity6"); + ExternalWorkflowStub arity6 = + Workflow.signalWithStartWorkflow( + six::start, + "input", + 2, + 3L, + true, + java.util.Collections.singletonList("nested"), + java.util.Collections.singletonMap("key", 4), + "arity6", + "queue", + six::signalValue, + "signal", + typedOptions); return sync.getExecution().getWorkflowId() + ":" + sync.getExecution().getRunId() @@ -197,7 +239,11 @@ public String run() { + "," + typedDefaults.getExecution().getWorkflowId() + ":" - + typedDefaults.getExecution().getRunId(); + + typedDefaults.getExecution().getRunId() + + "," + + arity6.getExecution().getWorkflowId() + + ":" + + arity6.getExecution().getRunId(); } } } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java index 863a105588..b9f67ee4f0 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -79,13 +79,15 @@ public String run() { .setIdConflictPolicy( WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) .build(); + Target target = Workflow.newExternalWorkflowStub(Target.class, id); ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( - Target.class, - w -> w.run("start"), + target::run, + "start", id, Workflow.getInfo().getTaskQueue(), - w -> w.notifySignal("first"), + target::notifySignal, + "first", options); assertEquals(id, external.getExecution().getWorkflowId()); Async.function( From 5e0683123baa643bc994f54f98e5eec1a9dd1375 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Wed, 21 Oct 2026 09:53:51 -0700 Subject: [PATCH 14/17] Merge workflow annotations through generated request hooks --- CHANGELOG.md | 1 + .../temporal/workflow/WorkflowOperations.java | 996 +++++++++++------- .../nexus/system/TemporalModelConverters.java | 18 +- .../ExternalWorkflowInvocationHandler.java | 20 +- temporal-sdk/src/main/nexus/README.md | 7 +- .../src/main/nexus/SIGNAL_WITH_START.md | 24 +- .../nexus/deps/nexus-temporal-types/model.wit | 1 + .../src/main/nexus/workflow-service.wit | 2 + .../TypedWorkflowMethodCaptureTest.java | 53 +- .../nexus/SignalWithStartWorkflowTest.java | 39 +- .../SystemSignalWithStartIntegrationTest.java | 3 + 11 files changed, 731 insertions(+), 433 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23357b121a..c41b208623 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ to docs, or any other relevant information. - Workflows can signal with start through the system workflow service using generated `Workflow.signalWithStartWorkflow(workflowType, workflowId, taskQueue, signalName, options)` API. Typed overloads accept bound workflow/signal methods followed directly by checked arguments. + Typed calls merge workflow retry/cron annotations with explicit options using generated Java-only WIT hooks. Request builders and operations are generated into `io.temporal.workflow`. System Nexus envelopes preserve destination workflow serialization context for nested payloads, codecs, and external payload storage. Requires a server supporting the system workflow service. diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java index 036bea5b63..bfbe386e2a 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java @@ -62,8 +62,9 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.Functions.Func workflow, @@ -82,8 +83,9 @@ public static io.temporal.workflow.ExternalWorkflowStub signalW * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.Functions.Func workflow, @@ -93,13 +95,14 @@ public static io.temporal.workflow.ExternalWorkflowStub signalW io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -124,9 +127,6 @@ public static io.temporal.workflow.ExternalWorkflowStub signalW requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -139,6 +139,12 @@ public static io.temporal.workflow.ExternalWorkflowStub signalW if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -147,8 +153,9 @@ public static io.temporal.workflow.ExternalWorkflowStub signalW * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -170,8 +177,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -183,13 +191,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -214,9 +223,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -229,6 +235,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -237,8 +249,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.Functions.Proc workflow, @@ -257,8 +270,9 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.Functions.Proc workflow, @@ -268,13 +282,14 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -299,9 +314,6 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -314,6 +326,12 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -322,8 +340,9 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.Functions.Proc workflow, @@ -344,8 +363,9 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithS * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.Functions.Proc workflow, @@ -356,13 +376,14 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithS io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -387,9 +408,6 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithS requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -402,6 +420,12 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithS if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -410,8 +434,9 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithS * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -433,8 +458,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -446,13 +472,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -477,9 +504,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -492,6 +516,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -500,8 +530,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -525,8 +556,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -539,13 +571,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -570,9 +603,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -585,6 +615,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -593,8 +629,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.Functions.Proc1 workflow, @@ -615,8 +652,9 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWit * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.Functions.Proc1 workflow, @@ -627,13 +665,14 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWit io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -658,9 +697,6 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWit requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -673,6 +709,12 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWit if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -681,8 +723,9 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWit * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -706,8 +749,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -720,13 +764,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -751,9 +796,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -766,6 +808,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -774,8 +822,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -799,8 +848,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -813,13 +863,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -844,9 +895,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -859,6 +907,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -867,8 +921,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -894,8 +949,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -909,13 +965,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -940,9 +997,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -955,6 +1009,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -963,8 +1023,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -988,8 +1049,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1002,13 +1064,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1033,9 +1096,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1048,6 +1108,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1056,8 +1122,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1083,8 +1150,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1098,13 +1166,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1129,9 +1198,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1144,6 +1210,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1152,8 +1224,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1181,8 +1254,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1198,13 +1272,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1229,9 +1304,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1244,6 +1316,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1252,8 +1330,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1283,8 +1362,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1301,13 +1381,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1332,9 +1413,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1347,6 +1425,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1355,8 +1439,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1382,8 +1467,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1397,13 +1483,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1428,9 +1515,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1443,6 +1527,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1451,8 +1541,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1480,8 +1571,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1496,13 +1588,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1527,9 +1620,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1542,6 +1632,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1550,8 +1646,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1581,8 +1678,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1599,13 +1697,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1630,9 +1729,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1645,6 +1741,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1653,8 +1755,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1686,8 +1789,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1705,13 +1809,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1736,9 +1841,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1751,6 +1853,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1759,8 +1867,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1790,8 +1899,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1808,13 +1918,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1839,9 +1950,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1854,6 +1962,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1862,8 +1976,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1895,8 +2010,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -1914,13 +2030,14 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -1945,9 +2062,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -1960,6 +2074,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -1968,8 +2088,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5, WorkflowResult> @@ -2007,8 +2128,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < WorkflowArg1, WorkflowArg2, WorkflowArg3, WorkflowArg4, WorkflowArg5, WorkflowResult> @@ -2032,13 +2154,16 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -2063,9 +2188,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -2078,6 +2200,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -2086,8 +2214,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < SignalArg1, @@ -2133,8 +2262,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < SignalArg1, @@ -2165,13 +2295,16 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -2196,9 +2329,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -2211,6 +2341,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -2219,8 +2355,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -2252,8 +2389,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -2271,13 +2409,16 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -2302,9 +2443,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -2317,6 +2455,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -2325,8 +2469,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -2360,8 +2505,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -2380,13 +2526,16 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> workflow.apply(workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -2411,9 +2560,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -2426,6 +2572,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -2434,8 +2586,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < WorkflowArg1, @@ -2482,8 +2635,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < WorkflowArg1, @@ -2515,15 +2669,21 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> - workflow.apply( - workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5, workflowArg6), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -2548,9 +2708,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -2563,6 +2720,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -2571,8 +2734,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < SignalArg1, @@ -2622,8 +2786,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < SignalArg1, @@ -2657,15 +2822,21 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> - workflow.apply( - workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5, workflowArg6), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -2690,9 +2861,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -2705,6 +2873,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -2713,8 +2887,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -2753,8 +2928,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( @@ -2778,15 +2954,21 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> - workflow.apply( - workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5, workflowArg6), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -2811,9 +2993,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -2826,6 +3005,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } @@ -2834,8 +3019,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < SignalArg1, @@ -2883,8 +3069,9 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( * Signal a workflow, starting it first if needed. * *

Pass bound method references followed by their arguments. SDK-owned call extractors probe - * these invocations. Supply invocation arguments as parameters, not in options. Other required - * fields remain explicit; automatic merging of probed options is not defined. + * these invocations. Supply invocation arguments as parameters, not in options. Fields with + * declared merge-from-function hooks merge explicit values with the named callable's metadata. + * Other required fields remain explicit. */ public static < SignalArg1, @@ -2916,15 +3103,21 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); - io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( - workflow, - () -> - workflow.apply( - workflowArg1, workflowArg2, workflowArg3, workflowArg4, workflowArg5, workflowArg6), - (capturedName, capturedArguments) -> { - requestBuilder.setWorkflow(capturedName); - requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); - }); + io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult workflowMetadata = + io.temporal.internal.nexus.system.TemporalModelConverters.captureWorkflowCall( + workflow, + () -> + workflow.apply( + workflowArg1, + workflowArg2, + workflowArg3, + workflowArg4, + workflowArg5, + workflowArg6), + (capturedName, capturedArguments) -> { + requestBuilder.setWorkflow(capturedName); + requestBuilder.setArgs(java.util.Arrays.asList(capturedArguments)); + }); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); io.temporal.internal.nexus.system.TemporalModelConverters.captureSignalCall( @@ -2949,9 +3142,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setIdReusePolicy(options.getIdReusePolicy()); if (options.getIdConflictPolicy() != null) requestBuilder.setIdConflictPolicy(options.getIdConflictPolicy()); - if (options.getRetryPolicy() != null) requestBuilder.setRetryPolicy(options.getRetryPolicy()); - if (options.getCronSchedule() != null) - requestBuilder.setCronSchedule(options.getCronSchedule()); if (options.getMemo() != null) requestBuilder.setMemo(options.getMemo()); if (options.getSearchAttributes() != null) requestBuilder.setSearchAttributes(options.getSearchAttributes()); @@ -2964,6 +3154,12 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( if (options.getStaticDetails() != null) requestBuilder.setStaticDetails(options.getStaticDetails()); } + requestBuilder.setRetryPolicy( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeMethodRetry( + workflowMetadata, options == null ? null : options.getRetryPolicy())); + requestBuilder.setCronSchedule( + io.temporal.internal.nexus.system.TemporalModelConverters.mergeCronSchedule( + workflowMetadata, options == null ? null : options.getCronSchedule())); io.temporal.workflow.SignalWithStartWorkflowRequest request = requestBuilder.build(); return executeSignalWithStartWorkflow(request); } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java index 8a6050be07..5795a645c4 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -2,6 +2,8 @@ import io.temporal.api.common.v1.*; import io.temporal.api.taskqueue.v1.TaskQueue; +import io.temporal.common.CronSchedule; +import io.temporal.common.MethodRetry; import io.temporal.common.RetryOptions; import io.temporal.common.VersioningOverride; import io.temporal.common.converter.DataConverter; @@ -31,11 +33,12 @@ public static String workflowNamespace() { } /** Captures one typed workflow invocation without starting a child workflow. */ - public static void captureWorkflowCall( + public static ExternalWorkflowInvocationHandler.ProbeResult captureWorkflowCall( Object method, Functions.Proc invocation, BiConsumer result) { ExternalWorkflowInvocationHandler.ProbeResult call = ExternalWorkflowInvocationHandler.probe(method, invocation, WorkflowMethodType.WORKFLOW); result.accept(call.getName(), call.getArguments()); + return call; } /** Captures one typed signal invocation without sending a signal. */ @@ -46,6 +49,19 @@ public static void captureSignalCall( result.accept(call.getName(), call.getArguments()); } + /** Merges the original method annotation with explicit retry settings. */ + public static RetryOptions mergeMethodRetry( + ExternalWorkflowInvocationHandler.ProbeResult call, RetryOptions explicit) { + return RetryOptions.merge(call.getMethod().getAnnotation(MethodRetry.class), explicit); + } + + /** Explicit schedules, including an empty string, override the method annotation. */ + public static String mergeCronSchedule( + ExternalWorkflowInvocationHandler.ProbeResult call, String explicit) { + CronSchedule annotation = call.getMethod().getAnnotation(CronSchedule.class); + return OptionsUtils.merge(annotation == null ? "" : annotation.value(), explicit, String.class); + } + public static WorkflowSerializationContext signalWithStartWorkflowSerializationContext( SignalWithStartWorkflowRequest request) { return new WorkflowSerializationContext(request.getNamespace(), request.getId()); diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java index aef6ff3a48..5469a2ce12 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/ExternalWorkflowInvocationHandler.java @@ -1,10 +1,6 @@ package io.temporal.internal.sync; import io.temporal.api.common.v1.WorkflowExecution; -import io.temporal.client.WorkflowOptions; -import io.temporal.common.CronSchedule; -import io.temporal.common.MethodRetry; -import io.temporal.common.RetryOptions; import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; import io.temporal.common.metadata.POJOWorkflowInterfaceMetadata; import io.temporal.common.metadata.POJOWorkflowMethodMetadata; @@ -77,24 +73,16 @@ public static final class ProbeResult { private final Object[] arguments; private final Class resultClass; private final Type resultType; - private final WorkflowOptions options; + private final Method method; private ProbeResult( ExternalWorkflowStub stub, POJOWorkflowMethodMetadata metadata, Object[] args) { this.stub = stub; this.name = metadata.getName(); this.arguments = args == null ? new Object[0] : args.clone(); - Method method = metadata.getWorkflowMethod(); + this.method = metadata.getWorkflowMethod(); this.resultClass = method.getReturnType(); this.resultType = method.getGenericReturnType(); - MethodRetry retry = method.getAnnotation(MethodRetry.class); - CronSchedule cron = method.getAnnotation(CronSchedule.class); - this.options = - WorkflowOptions.newBuilder() - .setWorkflowId(stub.getExecution().getWorkflowId()) - .setRetryOptions(RetryOptions.merge(retry, null)) - .setCronSchedule(cron == null ? null : cron.value()) - .build(); } public ExternalWorkflowStub getStub() { @@ -117,8 +105,8 @@ public Type getResultType() { return resultType; } - public WorkflowOptions getOptions() { - return options; + public Method getMethod() { + return method; } } diff --git a/temporal-sdk/src/main/nexus/README.md b/temporal-sdk/src/main/nexus/README.md index ebcb3dcb15..54c3165b2c 100644 --- a/temporal-sdk/src/main/nexus/README.md +++ b/temporal-sdk/src/main/nexus/README.md @@ -28,8 +28,11 @@ call-extractor hooks resolve annotated workflow/signal names and arguments without executing commands; the generated wrapper constructs the request. Primary callable arities zero through six and other callable arities zero or one come from Java rendering policy and the IDL's primary marker. No operation names -or composite-operation roles are encoded in the generator. Probed options remain -available in the SDK; automatic merging awaits IDL mapping and precedence rules. +or composite-operation roles are encoded in the generator. Java-only +`merge-from-function` hooks declare retry and cron merging from the workflow +method's original annotations. The generator retains raw probe metadata, and +SDK helpers apply normal client precedence without synthesizing `WorkflowOptions`. +Explicit ID/task queue and other options remain independent of stub metadata. The manifest derives from operation input/output protobuf transfer types. The service client's Java payload visitor generator consumes it, including payload-free response roots, without depending on compiled SDK classes. diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md index 70360bb4bd..b9a00ad855 100644 --- a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -43,17 +43,29 @@ the functional interface. The operation itself returns an external stub, not the workflow result. The existing external invocation handler probes method names, arguments, result -types, target execution, and annotation-derived retry/cron options using scoped +types, target execution, and the original annotated method using scoped thread locals. It sends no commands while probing and restores normal invocation behavior afterward, including on failure. Query/update methods and receiver lambdas are rejected. Typed calls reject `setArgs` or `setSignalArgs` in options. Both forms support `Async.function` and an overload omitting options. -Workflow ID and task queue remain explicit. The IDL does not define how probed -options map to request fields, precedence between those options and explicit -options, or relationships between the workflow and signal references. Automatic -options merging and cross-reference constraints are deferred rather than -hardcoded in the generator. Explicit ID, task queue, and options govern this call. +Typed calls merge the workflow method's `@MethodRetry` and `@CronSchedule` with +explicit retry/cron options, matching the client SDK. Retry fields use +`RetryOptions.merge(annotation, explicitOptions)`; explicit non-default settings +take precedence over annotation values. Cron uses the annotation when the +explicit value is null; an explicit empty string disables the annotated schedule. +The signal method's annotations are not used for these fields. Defaults apply +with null or omitted options. Untyped calls have no method annotations to merge. + +The shared WIT declares `@nexus.merge-from-function function="workflow"` hooks +on the retry and cron fields. Java generation retains the function's raw probe +metadata and calls the selected SDK merge helpers, without synthesizing +`WorkflowOptions` or hardcoding retry/cron policy in the generator. This directive +currently affects Java only. + +Workflow ID and task queue remain explicit. Relationships between workflow and +signal references are not declared and cross-reference constraints remain +deferred. Other options use their explicit values and existing defaults. `Workflow` inherits generated operations from `WorkflowOperations`. New WIT operations become available after regeneration, without adding handwritten diff --git a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit index 56c7f6fc78..606431dd9c 100644 --- a/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit +++ b/temporal-sdk/src/main/nexus/deps/nexus-temporal-types/model.wit @@ -92,6 +92,7 @@ interface model { /// dotnet-name-extractor="TemporalFunctionNames.WorkflowName" /// dotnet-call-extractor="TemporalFunctionNames.ExtractCall" /// java-call-extractor="captureWorkflowCall" + /// java-call-metadata-type="io.temporal.internal.sync.ExternalWorkflowInvocationHandler.ProbeResult" /// @nexus.add-rpc-compatible-with "workflow-type" type workflow-function = placeholder; diff --git a/temporal-sdk/src/main/nexus/workflow-service.wit b/temporal-sdk/src/main/nexus/workflow-service.wit index 459e4e5d72..88b821fa8b 100644 --- a/temporal-sdk/src/main/nexus/workflow-service.wit +++ b/temporal-sdk/src/main/nexus/workflow-service.wit @@ -77,8 +77,10 @@ interface workflow-service { /// @nexus.name go="WorkflowIDConflictPolicy" id-conflict-policy: option, /// @nexus.doc "Retry policy for the workflow." + /// @nexus.merge-from-function function="workflow" java="mergeMethodRetry" retry-policy: option, /// @nexus.doc "Cron schedule for recurring workflow executions. See https://docs.temporal.io/cron-job." + /// @nexus.merge-from-function function="workflow" java="mergeCronSchedule" cron-schedule: option, /// @nexus.doc "Memo for the workflow." memo: option, diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java index c1922b9041..14a84aca76 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TypedWorkflowMethodCaptureTest.java @@ -6,6 +6,7 @@ import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.common.CronSchedule; import io.temporal.common.MethodRetry; +import io.temporal.common.RetryOptions; import io.temporal.common.interceptors.WorkflowOutboundCallsInterceptor; import io.temporal.common.metadata.WorkflowMethodType; import io.temporal.internal.sync.ExternalWorkflowInvocationHandler; @@ -26,7 +27,12 @@ public interface Base { @WorkflowInterface public interface Target extends Base { @WorkflowMethod(name = "custom-workflow") - @MethodRetry(maximumAttempts = 3) + @MethodRetry( + initialIntervalSeconds = 7, + maximumAttempts = 3, + backoffCoefficient = 3, + maximumIntervalSeconds = 100, + doNotRetry = {"NoRetry"}) @CronSchedule("0 * * * *") int start(String value); @@ -62,7 +68,7 @@ private T stub(Class type, String id) { } @Test - public void probesNamesArgumentsOptionsAndReturnTypesWithoutCommands() { + public void probesNamesArgumentsAnnotationsAndReturnTypesWithoutCommands() { Target target = stub(Target.class, "target"); Functions.Func1 method = target::start; ProbeResult call = @@ -74,9 +80,9 @@ public void probesNamesArgumentsOptionsAndReturnTypesWithoutCommands() { assertArrayEquals(new Object[] {"input"}, call.getArguments()); assertEquals(int.class, call.getResultClass()); assertEquals(int.class, call.getResultType()); - assertEquals("target", call.getOptions().getWorkflowId()); - assertEquals(3, call.getOptions().getRetryOptions().getMaximumAttempts()); - assertEquals("0 * * * *", call.getOptions().getCronSchedule()); + assertEquals("target", call.getStub().getExecution().getWorkflowId()); + assertEquals(3, call.getMethod().getAnnotation(MethodRetry.class).maximumAttempts()); + assertEquals("0 * * * *", call.getMethod().getAnnotation(CronSchedule.class).value()); assertSame(ExternalWorkflowStub.fromTyped(target), call.getStub()); call.getArguments()[0] = "changed"; assertEquals("input", call.getArguments()[0]); @@ -99,6 +105,41 @@ public void probesNamesArgumentsOptionsAndReturnTypesWithoutCommands() { normalSignal, assertThrows(RuntimeException.class, () -> target.signal("outside", 1))); } + @Test + public void mergesOriginalAnnotationsWithExplicitValuesWithoutPrematureDefaults() { + Target target = stub(Target.class, "target"); + Functions.Func1 method = target::start; + ProbeResult call = + ExternalWorkflowInvocationHandler.probe( + method, () -> method.apply("input"), WorkflowMethodType.WORKFLOW); + RetryOptions defaults = TemporalModelConverters.mergeMethodRetry(call, null); + assertEquals(java.time.Duration.ofSeconds(7), defaults.getInitialInterval()); + assertEquals(3, defaults.getMaximumAttempts()); + assertEquals(3.0, defaults.getBackoffCoefficient(), 0); + RetryOptions explicit = RetryOptions.newBuilder().setMaximumAttempts(9).build(); + RetryOptions merged = TemporalModelConverters.mergeMethodRetry(call, explicit); + assertEquals(9, merged.getMaximumAttempts()); + assertEquals(java.time.Duration.ofSeconds(7), merged.getInitialInterval()); + assertEquals(java.time.Duration.ofSeconds(100), merged.getMaximumInterval()); + assertEquals(3.0, merged.getBackoffCoefficient(), 0); + assertArrayEquals(new String[] {"NoRetry"}, merged.getDoNotRetry()); + assertNull(explicit.getInitialInterval()); + assertEquals("0 * * * *", TemporalModelConverters.mergeCronSchedule(call, null)); + assertEquals("1 * * * *", TemporalModelConverters.mergeCronSchedule(call, "1 * * * *")); + assertEquals("", TemporalModelConverters.mergeCronSchedule(call, "")); + + GenericTarget plain = stub(GenericTarget.class, "plain"); + Functions.Func> plainMethod = plain::start; + ProbeResult noAnnotations = + ExternalWorkflowInvocationHandler.probe( + plainMethod, () -> plainMethod.apply(), WorkflowMethodType.WORKFLOW); + assertNull(TemporalModelConverters.mergeMethodRetry(noAnnotations, null)); + assertSame(explicit, TemporalModelConverters.mergeMethodRetry(noAnnotations, explicit)); + assertNull(TemporalModelConverters.mergeCronSchedule(noAnnotations, null)); + assertEquals("", TemporalModelConverters.mergeCronSchedule(noAnnotations, "")); + verifyNoInteractions(outbound); + } + @Test public void rejectsMissingRepeatedWrongKindAndNonBoundInvocations() { Target target = stub(Target.class, "target"); @@ -211,6 +252,6 @@ private String parallelProbe( method.apply(value); }, WorkflowMethodType.WORKFLOW); - return result.getOptions().getWorkflowId() + ":" + result.getArguments()[0]; + return result.getStub().getExecution().getWorkflowId() + ":" + result.getArguments()[0]; } } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java index c4c55f1cfb..95491385b1 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -43,6 +43,22 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { request.getNamespace()); assertEquals("notify", request.getSignal()); assertEquals("queue", request.getTaskQueue()); + if (request.getId().startsWith("typed")) { + assertEquals( + java.time.Duration.ofSeconds(7), + request.getRetryPolicy().getInitialInterval()); + assertEquals( + request.getId().equals("typed-async") ? 9 : 3, + request.getRetryPolicy().getMaximumAttempts()); + assertEquals( + request.getId().equals("typed-async") + ? "" + : "0 * * * *", + request.getCronSchedule()); + } else { + assertNull(request.getRetryPolicy()); + assertNull(request.getCronSchedule()); + } assertEquals( io.temporal.api.enums.v1.WorkflowIdReusePolicy .WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE, @@ -94,22 +110,28 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { @Test public void generatedWorkflowMethodsReturnExternalStubs() { assertEquals( - "sync:run,async:run,defaults:run,typed:run,typed-async:run,typed-defaults:run,arity6:run", + "sync:run,async:run,defaults:run,typed:run,typed-async:run,typed-defaults:run,typed-null-defaults:run,arity6:run", rule.newWorkflowStubTimeoutOptions(Caller.class).run()); } @WorkflowInterface public interface TypedTarget { @WorkflowMethod(name = "Target") + @io.temporal.common.MethodRetry(initialIntervalSeconds = 7, maximumAttempts = 3) + @io.temporal.common.CronSchedule("0 * * * *") int start(String input); @SignalMethod(name = "notify") + @io.temporal.common.MethodRetry(maximumAttempts = 99) + @io.temporal.common.CronSchedule("signal-annotation-must-not-be-used") void signalValue(String value); } @WorkflowInterface public interface EmptyTarget { @WorkflowMethod(name = "Target") + @io.temporal.common.MethodRetry(initialIntervalSeconds = 7, maximumAttempts = 3) + @io.temporal.common.CronSchedule("0 * * * *") void start(); @SignalMethod(name = "notify") @@ -185,12 +207,21 @@ public String run() { "queue", target::signalValue, "signal", - typedOptions)) + typedOptions.toBuilder() + .setRetryPolicy( + io.temporal.common.RetryOptions.newBuilder() + .setMaximumAttempts(9) + .build()) + .setCronSchedule("") + .build())) .get(); EmptyTarget empty = Workflow.newExternalWorkflowStub(EmptyTarget.class, "typed-defaults"); ExternalWorkflowStub typedDefaults = Workflow.signalWithStartWorkflow( empty::start, "typed-defaults", "queue", empty::signalValue); + ExternalWorkflowStub typedNull = + Workflow.signalWithStartWorkflow( + empty::start, "typed-null-defaults", "queue", empty::signalValue, null); assertThrows( IllegalArgumentException.class, () -> @@ -241,6 +272,10 @@ public String run() { + ":" + typedDefaults.getExecution().getRunId() + "," + + typedNull.getExecution().getWorkflowId() + + ":" + + typedNull.getExecution().getRunId() + + "," + arity6.getExecution().getWorkflowId() + ":" + arity6.getExecution().getRunId(); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java index b9f67ee4f0..aa80eb878a 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -43,6 +43,8 @@ public void startsThenSignalsTheExistingExecutionAndReplays() throws Exception { @WorkflowInterface public interface Target { @WorkflowMethod(name = "SystemSignalTarget") + @io.temporal.common.MethodRetry(initialIntervalSeconds = 1, maximumAttempts = 3) + @io.temporal.common.CronSchedule("0 * * * *") String run(String initial); @SignalMethod @@ -76,6 +78,7 @@ public String run() { String id = Workflow.getInfo().getWorkflowId() + "-target"; SignalWithStartWorkflowOptions options = SignalWithStartWorkflowOptions.newBuilder() + .setCronSchedule("") .setIdConflictPolicy( WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) .build(); From 2871c1c6493da12d00529e650bd352993d109d11 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Wed, 21 Oct 2026 12:46:49 -0700 Subject: [PATCH 15/17] Keep signal-with-start arguments out of generated options --- CHANGELOG.md | 2 +- .../SignalWithStartWorkflowOptions.java | 46 ----- .../temporal/workflow/WorkflowOperations.java | 184 ++---------------- .../src/main/nexus/SIGNAL_WITH_START.md | 15 +- .../nexus/SignalWithStartWorkflowTest.java | 55 +++--- .../SystemSignalWithStartIntegrationTest.java | 15 +- 6 files changed, 53 insertions(+), 264 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c41b208623..74e1871b90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ to docs, or any other relevant information. ### Added - Workflows can signal with start through the system workflow service using - generated `Workflow.signalWithStartWorkflow(workflowType, workflowId, taskQueue, signalName, options)` API. + generated `Workflow.signalWithStartWorkflow(workflowType, args, workflowId, taskQueue, signalName, signalArgs, options)` API. Typed overloads accept bound workflow/signal methods followed directly by checked arguments. Typed calls merge workflow retry/cron annotations with explicit options using generated Java-only WIT hooks. Request builders and operations are generated into `io.temporal.workflow`. diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java index 7c37993610..0811f712e7 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/SignalWithStartWorkflowOptions.java @@ -4,12 +4,6 @@ /** Signal a workflow, starting it first if needed. */ @SuppressWarnings({"unchecked", "rawtypes"}) public final class SignalWithStartWorkflowOptions { - /** Arguments for the workflow. */ - private final java.util.List args; - - /** Arguments for the signal. */ - private final java.util.List signalArgs; - /** * Total workflow execution timeout, including retries and continue-as-new. Defaults to unlimited. */ @@ -70,8 +64,6 @@ public static SignalWithStartWorkflowOptions getDefaultInstance() { } private SignalWithStartWorkflowOptions( - java.util.List args, - java.util.List signalArgs, java.time.Duration executionTimeout, java.time.Duration runTimeout, java.time.Duration taskTimeout, @@ -86,8 +78,6 @@ private SignalWithStartWorkflowOptions( java.time.Duration startDelay, String staticSummary, String staticDetails) { - this.args = args; - this.signalArgs = signalArgs; this.executionTimeout = executionTimeout; this.runTimeout = runTimeout; this.taskTimeout = taskTimeout; @@ -104,14 +94,6 @@ private SignalWithStartWorkflowOptions( this.staticDetails = staticDetails; } - public java.util.List getArgs() { - return args; - } - - public java.util.List getSignalArgs() { - return signalArgs; - } - public java.time.Duration getExecutionTimeout() { return executionTimeout; } @@ -185,8 +167,6 @@ private Builder() {} private Builder(SignalWithStartWorkflowOptions value) { if (value == null) return; - this.args = value.args; - this.signalArgs = value.signalArgs; this.executionTimeout = value.executionTimeout; this.runTimeout = value.runTimeout; this.taskTimeout = value.taskTimeout; @@ -203,30 +183,6 @@ private Builder(SignalWithStartWorkflowOptions value) { this.staticDetails = value.staticDetails; } - private java.util.List args = null; - - public Builder setArgs(java.util.List value) { - this.args = value; - return this; - } - - public Builder setArgs(Object... values) { - this.args = values == null ? null : java.util.Arrays.asList(values); - return this; - } - - private java.util.List signalArgs = null; - - public Builder setSignalArgs(java.util.List value) { - this.signalArgs = value; - return this; - } - - public Builder setSignalArgs(Object... values) { - this.signalArgs = values == null ? null : java.util.Arrays.asList(values); - return this; - } - private java.time.Duration executionTimeout = null; public Builder setExecutionTimeout(java.time.Duration value) { @@ -328,8 +284,6 @@ public Builder setStaticDetails(String value) { public SignalWithStartWorkflowOptions build() { return new SignalWithStartWorkflowOptions( - args, - signalArgs, executionTimeout, runTimeout, taskTimeout, diff --git a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java index bfbe386e2a..64e487a6d8 100644 --- a/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java +++ b/temporal-sdk/src/main/generated/io/temporal/workflow/WorkflowOperations.java @@ -6,31 +6,41 @@ public abstract class WorkflowOperations { protected WorkflowOperations() {} public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( - String workflow, String id, String taskQueue, String signal) { + String workflow, + Object[] args, + String id, + String taskQueue, + String signal, + Object[] signalArgs) { return signalWithStartWorkflow( workflow, + args, id, taskQueue, signal, + signalArgs, io.temporal.workflow.SignalWithStartWorkflowOptions.getDefaultInstance()); } /** Signal a workflow, starting it first if needed. */ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( String workflow, + Object[] args, String id, String taskQueue, String signal, + Object[] signalArgs, io.temporal.workflow.SignalWithStartWorkflowOptions options) { io.temporal.workflow.SignalWithStartWorkflowRequest.Builder requestBuilder = io.temporal.workflow.SignalWithStartWorkflowRequest.newBuilder(); + requestBuilder.setArgs(java.util.Arrays.asList(java.util.Objects.requireNonNull(args, "args"))); requestBuilder.setWorkflow(java.util.Objects.requireNonNull(workflow, "workflow")); requestBuilder.setId(java.util.Objects.requireNonNull(id, "id")); requestBuilder.setTaskQueue(java.util.Objects.requireNonNull(taskQueue, "taskQueue")); + requestBuilder.setSignalArgs( + java.util.Arrays.asList(java.util.Objects.requireNonNull(signalArgs, "signalArgs"))); requestBuilder.setSignal(java.util.Objects.requireNonNull(signal, "signal")); if (options != null) { - if (options.getArgs() != null) requestBuilder.setArgs(options.getArgs()); - if (options.getSignalArgs() != null) requestBuilder.setSignalArgs(options.getSignalArgs()); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -113,12 +123,6 @@ public static io.temporal.workflow.ExternalWorkflowStub signalW requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -209,12 +213,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -300,12 +298,6 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -394,12 +386,6 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWithS requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -490,12 +476,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -589,12 +569,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -683,12 +657,6 @@ public static io.temporal.workflow.ExternalWorkflowStub signalWit requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -782,12 +750,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -881,12 +843,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -983,12 +939,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -1082,12 +1032,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -1184,12 +1128,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -1290,12 +1228,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -1399,12 +1331,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -1501,12 +1427,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -1606,12 +1526,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -1715,12 +1629,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -1827,12 +1735,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -1936,12 +1838,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -2048,12 +1944,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -2174,12 +2064,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -2315,12 +2199,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -2429,12 +2307,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -2546,12 +2418,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -2694,12 +2560,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -2847,12 +2707,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -2979,12 +2833,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); @@ -3128,12 +2976,6 @@ io.temporal.workflow.ExternalWorkflowStub signalWithStartWorkflow( requestBuilder.setSignalArgs(java.util.Arrays.asList(capturedArguments)); }); if (options != null) { - if (options.getArgs() != null) - throw new IllegalArgumentException( - "args must be supplied through the bound call, not options"); - if (options.getSignalArgs() != null) - throw new IllegalArgumentException( - "signalArgs must be supplied through the bound call, not options"); if (options.getExecutionTimeout() != null) requestBuilder.setExecutionTimeout(options.getExecutionTimeout()); if (options.getRunTimeout() != null) requestBuilder.setRunTimeout(options.getRunTimeout()); diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md index b9a00ad855..5871b44d2d 100644 --- a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -5,25 +5,25 @@ when necessary. It requires a server supporting the system workflow service. ```java ExternalWorkflowStub external = Workflow.signalWithStartWorkflow( - "TargetWorkflow", "target", "target-queue", "notify", + "TargetWorkflow", new Object[] {input}, "target", "target-queue", + "notify", new Object[] {signal}, SignalWithStartWorkflowOptions.newBuilder() - .setArgs(input) - .setSignalArgs(signal) + .setRunTimeout(timeout) .build()); ``` Import `Workflow`, `SignalWithStartWorkflowOptions`, and `ExternalWorkflowStub` from `io.temporal.workflow`. The generated options builder contains the API's options, including timeouts, retry policy, memo, conflict policy, and flattened -static summary/details setters. Workflow type, ID, task queue, and signal name +static summary/details setters. Workflow type, argument array, ID, task queue, signal name, and signal argument array are required parameters. An overload without options uses defaults. The request is constructed internally. Namespace defaults to the caller's namespace. Request ID is omitted: the system service manages it. The call returns after signal delivery/start completes. The returned external stub supports further signals and cancellation. Use -`Async.function(Workflow::signalWithStartWorkflow, workflowType, workflowId, -taskQueue, signalName, options)` for a promise. +`Async.function(() -> Workflow.signalWithStartWorkflow(workflowType, args, +workflowId, taskQueue, signalName, signalArgs, options))` for a promise. The typed overload checks workflow and signal arguments against their interface: @@ -46,7 +46,8 @@ The existing external invocation handler probes method names, arguments, result types, target execution, and the original annotated method using scoped thread locals. It sends no commands while probing and restores normal invocation behavior afterward, including on failure. Query/update methods and receiver -lambdas are rejected. Typed calls reject `setArgs` or `setSignalArgs` in options. +lambdas are rejected. Both APIs take invocation arguments directly; options do +not contain argument fields. Both forms support `Async.function` and an overload omitting options. Typed calls merge the workflow method's `@MethodRetry` and `@CronSchedule` with diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java index 95491385b1..f1c3c96b49 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SignalWithStartWorkflowTest.java @@ -64,13 +64,8 @@ public void init(WorkflowOutboundCallsInterceptor outbound) { .WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE, request.getIdReusePolicy()); if (request.getId().contains("defaults")) { - if (request.getId().equals("defaults")) { - assertNull(request.getArgs()); - assertNull(request.getSignalArgs()); - } else { - assertTrue(request.getArgs().isEmpty()); - assertTrue(request.getSignalArgs().isEmpty()); - } + assertTrue(request.getArgs().isEmpty()); + assertTrue(request.getSignalArgs().isEmpty()); } else { assertEquals("input", request.getArgs().get(0)); if (request.getId().equals("arity6")) { @@ -164,29 +159,34 @@ public static class CallerImpl implements Caller { public String run() { SignalWithStartWorkflowOptions options = SignalWithStartWorkflowOptions.newBuilder() - .setArgs("input") - .setSignalArgs("signal") .setStaticSummary("summary") .setRunTimeout(java.time.Duration.ofMinutes(3)) .build(); ExternalWorkflowStub sync = - Workflow.signalWithStartWorkflow("Target", "sync", "queue", "notify", options); + Workflow.signalWithStartWorkflow( + "Target", + new Object[] {"input"}, + "sync", + "queue", + "notify", + new Object[] {"signal"}, + options); ExternalWorkflowStub async = Async.function( - Workflow::signalWithStartWorkflow, - "Target", - "async", - "queue", - "notify", - options.toBuilder().build()) + () -> + Workflow.signalWithStartWorkflow( + "Target", + new Object[] {"input"}, + "async", + "queue", + "notify", + new Object[] {"signal"}, + options.toBuilder().build())) .get(); ExternalWorkflowStub defaults = - Workflow.signalWithStartWorkflow("Target", "defaults", "queue", "notify"); - SignalWithStartWorkflowOptions typedOptions = - SignalWithStartWorkflowOptions.newBuilder() - .setStaticSummary("summary") - .setRunTimeout(java.time.Duration.ofMinutes(3)) - .build(); + Workflow.signalWithStartWorkflow( + "Target", new Object[0], "defaults", "queue", "notify", new Object[0]); + SignalWithStartWorkflowOptions typedOptions = options; TypedTarget target = Workflow.newExternalWorkflowStub(TypedTarget.class, "typed"); ExternalWorkflowStub typed = Workflow.signalWithStartWorkflow( @@ -222,17 +222,6 @@ public String run() { ExternalWorkflowStub typedNull = Workflow.signalWithStartWorkflow( empty::start, "typed-null-defaults", "queue", empty::signalValue, null); - assertThrows( - IllegalArgumentException.class, - () -> - Workflow.signalWithStartWorkflow( - target::start, - "input", - "invalid", - "queue", - target::signalValue, - "signal", - options)); SixArgumentTarget six = Workflow.newExternalWorkflowStub(SixArgumentTarget.class, "arity6"); ExternalWorkflowStub arity6 = Workflow.signalWithStartWorkflow( diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java index aa80eb878a..b266a0d437 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -94,12 +94,15 @@ public String run() { options); assertEquals(id, external.getExecution().getWorkflowId()); Async.function( - Workflow::signalWithStartWorkflow, - "SystemSignalTarget", - id, - Workflow.getInfo().getTaskQueue(), - "notifySignal", - options.toBuilder().setArgs("ignored").setSignalArgs("second").build()) + () -> + Workflow.signalWithStartWorkflow( + "SystemSignalTarget", + new Object[] {"ignored"}, + id, + Workflow.getInfo().getTaskQueue(), + "notifySignal", + new Object[] {"second"}, + options)) .get(); return id; } From c1f8df340e8af6bff4285339e14ee7058956d25f Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Wed, 21 Oct 2026 13:10:01 -0700 Subject: [PATCH 16/17] Verify system workflow codec contexts and reject unknown overrides --- .../nexus/system/TemporalModelConverters.java | 7 +- .../src/main/nexus/SIGNAL_WITH_START.md | 5 + .../system/TemporalModelConvertersTest.java | 68 +++++++ .../SystemSignalWithStartIntegrationTest.java | 175 +++++++++++++++++- 4 files changed, 250 insertions(+), 5 deletions(-) create mode 100644 temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TemporalModelConvertersTest.java diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java index 5795a645c4..9de4ee0fa4 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -182,16 +182,17 @@ public static io.temporal.api.workflow.v1.VersioningOverride versioningOverrideT @SuppressWarnings("deprecation") public static VersioningOverride versioningOverrideFromProto( DataConverter converter, io.temporal.api.workflow.v1.VersioningOverride value) { - if (value.hasOneTime()) + if (value.hasOneTime() && value.getOneTime().hasTargetDeploymentVersion()) return new VersioningOverride.OneTimeVersioningOverride( deployment(value.getOneTime().getTargetDeploymentVersion())); - if (value.hasPinned()) + if (value.hasPinned() && value.getPinned().hasVersion()) return new VersioningOverride.PinnedVersioningOverride( deployment(value.getPinned().getVersion())); if (!value.getPinnedVersion().isEmpty()) return new VersioningOverride.PinnedVersioningOverride( io.temporal.common.WorkerDeploymentVersion.fromCanonicalString(value.getPinnedVersion())); - return new VersioningOverride.AutoUpgradeVersioningOverride(); + if (value.getAutoUpgrade()) return new VersioningOverride.AutoUpgradeVersioningOverride(); + throw new IllegalArgumentException("Unknown versioning override proto shape"); } private static io.temporal.common.WorkerDeploymentVersion deployment( diff --git a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md index 5871b44d2d..e550dd3927 100644 --- a/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md +++ b/temporal-sdk/src/main/nexus/SIGNAL_WITH_START.md @@ -75,6 +75,11 @@ fields, and serialization-context hook are declared in WIT. The converter uses the destination namespace and workflow ID for nested payloads, codecs, and failures; the outer system envelope remains server-readable. +`SystemSignalWithStartIntegrationTest` verifies this converter selection against a +supporting server with a signing codec, overlapping calls to distinct destination +workflows, payload inspection in history, and replay. Converter unit tests cover +valid and unknown versioning override shapes; unknown shapes are rejected. + This operation serializes the request and deserializes a response with no user payloads. Future operations returning embedded payloads must use generic response models and propagate concrete result types from the API to transfer conversion. diff --git a/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TemporalModelConvertersTest.java b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TemporalModelConvertersTest.java new file mode 100644 index 0000000000..c5ada24373 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/internal/nexus/system/TemporalModelConvertersTest.java @@ -0,0 +1,68 @@ +package io.temporal.internal.nexus.system; + +import static org.junit.Assert.*; + +import io.temporal.common.VersioningOverride; +import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.common.converter.DataConverter; +import io.temporal.common.converter.DefaultDataConverter; +import org.junit.Test; + +public class TemporalModelConvertersTest { + private static final DataConverter CONVERTER = DefaultDataConverter.STANDARD_INSTANCE; + + @Test + @SuppressWarnings("deprecation") + public void versioningOverridesRoundTripKnownShapes() { + WorkerDeploymentVersion version = new WorkerDeploymentVersion("deployment", "build"); + VersioningOverride.PinnedVersioningOverride pinned = + (VersioningOverride.PinnedVersioningOverride) + roundTrip(new VersioningOverride.PinnedVersioningOverride(version)); + assertEquals(version, pinned.getVersion()); + VersioningOverride.OneTimeVersioningOverride oneTime = + (VersioningOverride.OneTimeVersioningOverride) + roundTrip(new VersioningOverride.OneTimeVersioningOverride(version)); + assertEquals(version, oneTime.getTargetVersion()); + assertTrue( + roundTrip(new VersioningOverride.AutoUpgradeVersioningOverride()) + instanceof VersioningOverride.AutoUpgradeVersioningOverride); + VersioningOverride.PinnedVersioningOverride legacy = + (VersioningOverride.PinnedVersioningOverride) + TemporalModelConverters.versioningOverrideFromProto( + CONVERTER, + io.temporal.api.workflow.v1.VersioningOverride.newBuilder() + .setPinnedVersion("deployment.build") + .build()); + assertEquals(version, legacy.getVersion()); + } + + @Test + public void rejectsEmptyAndIncompleteVersioningOverrides() { + for (io.temporal.api.workflow.v1.VersioningOverride value : + new io.temporal.api.workflow.v1.VersioningOverride[] { + io.temporal.api.workflow.v1.VersioningOverride.getDefaultInstance(), + io.temporal.api.workflow.v1.VersioningOverride.newBuilder().setAutoUpgrade(false).build(), + io.temporal.api.workflow.v1.VersioningOverride.newBuilder() + .setPinned( + io.temporal.api.workflow.v1.VersioningOverride.PinnedOverride + .getDefaultInstance()) + .build(), + io.temporal.api.workflow.v1.VersioningOverride.newBuilder() + .setOneTime( + io.temporal.api.workflow.v1.VersioningOverride.OneTimeOverride + .getDefaultInstance()) + .build() + }) { + IllegalArgumentException error = + assertThrows( + IllegalArgumentException.class, + () -> TemporalModelConverters.versioningOverrideFromProto(CONVERTER, value)); + assertEquals("Unknown versioning override proto shape", error.getMessage()); + } + } + + private static VersioningOverride roundTrip(VersioningOverride value) { + return TemporalModelConverters.versioningOverrideFromProto( + CONVERTER, TemporalModelConverters.versioningOverrideToProto(CONVERTER, value)); + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java index b266a0d437..ea0266a127 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/nexus/SystemSignalWithStartIntegrationTest.java @@ -1,13 +1,28 @@ package io.temporal.workflow.nexus; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; +import com.google.protobuf.ByteString; +import io.temporal.api.common.v1.Payload; import io.temporal.api.enums.v1.WorkflowIdConflictPolicy; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.common.converter.CodecDataConverter; +import io.temporal.common.converter.DefaultDataConverter; +import io.temporal.internal.payload.visitor.SystemNexusPayloads; +import io.temporal.payload.codec.PayloadCodec; +import io.temporal.payload.context.SerializationContext; +import io.temporal.payload.context.WorkflowSerializationContext; import io.temporal.testing.CloudTestExclusion.RequiresCloudProvisioning; import io.temporal.testing.CloudTestExclusionNote; import io.temporal.testing.WorkflowReplayer; import io.temporal.testing.internal.SDKTestWorkflowRule; import io.temporal.workflow.*; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; import org.junit.Assume; import org.junit.Before; import org.junit.Rule; @@ -19,7 +34,16 @@ public class SystemSignalWithStartIntegrationTest { @Rule public SDKTestWorkflowRule rule = - SDKTestWorkflowRule.newBuilder().setWorkflowTypes(CallerImpl.class, TargetImpl.class).build(); + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(CallerImpl.class, ConcurrentCallerImpl.class, TargetImpl.class) + .setWorkflowClientOptions( + WorkflowClientOptions.newBuilder() + .setDataConverter( + new CodecDataConverter( + DefaultDataConverter.STANDARD_INSTANCE, + Collections.singletonList(new DestinationCodec(null)))) + .build()) + .build(); @Before public void requireSystemService() { @@ -40,6 +64,153 @@ public void startsThenSignalsTheExistingExecutionAndReplays() throws Exception { WorkflowReplayer.replayWorkflowExecution(rule.getExecutionHistory(callerId), rule.getWorker()); } + @Test + public void concurrentCallsUseDestinationCodecContextAndPreserveOuterEnvelopes() + throws Exception { + ConcurrentCaller caller = rule.newWorkflowStubTimeoutOptions(ConcurrentCaller.class); + List targets = caller.run(); + for (String target : targets) { + assertEquals( + "start:first:second", + rule.getWorkflowClient().newUntypedWorkflowStub(target).getResult(String.class)); + } + String callerId = WorkflowStub.fromTyped(caller).getExecution().getWorkflowId(); + int scheduled = 0; + for (HistoryEvent event : rule.getExecutionHistory(callerId).getEvents()) { + if (!event.hasNexusOperationScheduledEventAttributes()) continue; + scheduled++; + Payload envelope = event.getNexusOperationScheduledEventAttributes().getInput(); + assertTrue(SystemNexusPayloads.isSystemPayload(envelope)); + assertFalse(envelope.containsMetadata(DestinationCodec.KEY)); + SignalWithStartWorkflowExecutionRequest request = + SignalWithStartWorkflowExecutionRequest.parseFrom(envelope.getData()); + assertTrue(targets.contains(request.getWorkflowId())); + String expected = request.getNamespace() + "/" + request.getWorkflowId(); + List embedded = new ArrayList<>(); + embedded.addAll(request.getInput().getPayloadsList()); + embedded.addAll(request.getSignalInput().getPayloadsList()); + embedded.addAll(request.getMemo().getFieldsMap().values()); + embedded.add(request.getUserMetadata().getSummary()); + embedded.add(request.getUserMetadata().getDetails()); + assertEquals(5, embedded.size()); + for (Payload payload : embedded) { + assertEquals(expected, payload.getMetadataOrThrow(DestinationCodec.KEY).toStringUtf8()); + } + } + assertEquals(4, scheduled); + WorkflowReplayer.replayWorkflowExecution(rule.getExecutionHistory(callerId), rule.getWorker()); + } + + @WorkflowInterface + public interface ConcurrentCaller { + @WorkflowMethod + List run(); + } + + public static class ConcurrentCallerImpl implements ConcurrentCaller { + @Override + public List run() { + List targets = + Arrays.asList( + Workflow.getInfo().getWorkflowId() + "-first", + Workflow.getInfo().getWorkflowId() + "-second"); + List> calls = new ArrayList<>(); + for (String id : targets) { + calls.add( + Async.procedure( + () -> { + SignalWithStartWorkflowOptions options = + SignalWithStartWorkflowOptions.newBuilder() + .setCronSchedule("") + .setIdConflictPolicy( + WorkflowIdConflictPolicy.WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING) + .setMemo(Collections.singletonMap("memo", "memo-value")) + .setStaticSummary("summary") + .setStaticDetails("details") + .build(); + Target target = Workflow.newExternalWorkflowStub(Target.class, id); + Workflow.signalWithStartWorkflow( + target::run, + "start", + id, + Workflow.getInfo().getTaskQueue(), + target::notifySignal, + "first", + options); + Workflow.signalWithStartWorkflow( + "SystemSignalTarget", + new Object[] {"ignored"}, + id, + Workflow.getInfo().getTaskQueue(), + "notifySignal", + new Object[] {"second"}, + options); + })); + } + Promise.allOf(calls).get(); + return targets; + } + } + + private static final class DestinationCodec implements PayloadCodec { + static final String KEY = "test-destination"; + private final String destination; + + DestinationCodec(String destination) { + this.destination = destination; + } + + @Nonnull + @Override + public PayloadCodec withContext(@Nonnull SerializationContext context) { + if (!(context instanceof WorkflowSerializationContext)) return this; + WorkflowSerializationContext workflow = (WorkflowSerializationContext) context; + return new DestinationCodec(workflow.getNamespace() + "/" + workflow.getWorkflowId()); + } + + @Nonnull + @Override + public List encode(@Nonnull List payloads) { + return payloads.stream() + .map( + payload -> { + rejectEnvelope(payload); + assertFalse("Payload encoded twice", payload.containsMetadata(KEY)); + return destination == null + ? payload + : payload.toBuilder() + .putMetadata(KEY, ByteString.copyFromUtf8(destination)) + .build(); + }) + .collect(Collectors.toList()); + } + + @Nonnull + @Override + public List decode(@Nonnull List payloads) { + return payloads.stream() + .map( + payload -> { + rejectEnvelope(payload); + if (!payload.containsMetadata(KEY)) return payload; + assertEquals(destination, payload.getMetadataOrThrow(KEY).toStringUtf8()); + return payload.toBuilder().removeMetadata(KEY).build(); + }) + .collect(Collectors.toList()); + } + + private static void rejectEnvelope(Payload payload) { + assertFalse( + "System envelope passed to the user codec", SystemNexusPayloads.isSystemPayload(payload)); + ByteString type = payload.getMetadataMap().get("messageType"); + assertFalse( + "Unmarked system response passed to the user codec", + type != null + && type.toStringUtf8() + .startsWith("temporal.api.workflowservice.v1.SignalWithStartWorkflowExecution")); + } + } + @WorkflowInterface public interface Target { @WorkflowMethod(name = "SystemSignalTarget") From a2394fde107f9e04e4a791cafc18d71ecb2aabf3 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Wed, 21 Oct 2026 13:17:45 -0700 Subject: [PATCH 17/17] Reuse SDK memo payload map conversion --- .../internal/nexus/system/TemporalModelConverters.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java index 9de4ee0fa4..6035f38fe1 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/system/TemporalModelConverters.java @@ -112,9 +112,7 @@ public static RetryOptions retryPolicyFromProto(DataConverter converter, RetryPo } public static Memo memoToProto(DataConverter converter, Map value) { - Memo.Builder builder = Memo.newBuilder(); - value.forEach((key, item) -> builder.putFields(key, converter.toPayload(item).get())); - return builder.build(); + return Memo.newBuilder().putAllFields(HeaderUtils.intoPayloadMap(converter, value)).build(); } public static Map memoFromProto(DataConverter converter, Memo value) {