Skip to content

Commit

Permalink
Support Proto 3 and 4 (#2383)
Browse files Browse the repository at this point in the history
Support Proto 3 and 4
  • Loading branch information
Quinn-With-Two-Ns authored Jan 28, 2025
1 parent c51e5d1 commit 8b17a52
Show file tree
Hide file tree
Showing 22 changed files with 61 additions and 50 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ or to *build.gradle*:

compile group: 'io.temporal', name: 'temporal-sdk', version: 'N.N.N'

## Protobuf 3.x vs 4.x

The Temporal Java SDK currently supports `protobuf-java` 3.x and 4.x. To support these, the Temporal Java SDK allows any protobuf library >= 3.25.
Temporal strongly recommends using the latest `protobuf-java` 4.x library unless you absolutely cannot.
If you cannot use protobuf-java 3.25 >=, you can try `temporal-shaded` which includes a shaded version of the `protobuf-java` library.

## Contributing

We'd love your help in improving the Temporal Java SDK. Please review our [contribution guidelines](CONTRIBUTING.md).
Expand Down
17 changes: 9 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
}

plugins {
id 'net.ltgt.errorprone' version '4.0.1' apply false
id 'net.ltgt.errorprone' version '4.1.0' apply false
id 'org.cadixdev.licenser' version '0.6.1'
id 'com.palantir.git-version' version "${palantirGitVersionVersion}" apply false
id 'io.github.gradle-nexus.publish-plugin' version '1.3.0'
Expand All @@ -29,7 +29,7 @@ allprojects {

ext {
// Platforms
grpcVersion = '1.54.1' // [1.38.0,) Needed for io.grpc.protobuf.services.HealthStatusManager
grpcVersion = '1.58.1' // [1.38.0,) Needed for io.grpc.protobuf.services.HealthStatusManager
jacksonVersion = '2.14.2' // [2.9.0,)
nexusVersion = '0.3.0-alpha'
// we don't upgrade to 1.10.x because it requires kotlin 1.6. Users may use 1.10.x in their environments though.
Expand All @@ -38,12 +38,13 @@ ext {
// stay on 1.x for a while to don't use any APIs from 2.x which may break our users which still stay on 1.x
// also slf4j 2.x is not compatible with spring boot 2.x
slf4jVersion = project.hasProperty("edgeDepsTest") ? '2.0.16' : '1.7.36' // [1.4.0,)
// [3.12.0,)
// 3.12 is brought by min gRPC 1.38.
// We can't move pass 3.22.0 because 3.22.2 deprecates some methods used by generated code produced by
// the old protoc we keep for compatibility of our generated code with old protobuf-java versions.
// Which leads to build failure because of -Werror.
protoVersion = '3.22.0'
// [3.25.5,)
// 3.25.5 is required because of our protoc compiler 25.x. The proto version must be the same or greater then the protoc version.
// We use this version of protoc because it will generate code that is compatible with protobuf-java 3.x and 4.x.
// We don't move past 3.25.x because the next version is a major version bump and we don't want to break our users.
//
// For more information see: https://github.com/grpc/grpc-java/issues/11015#issuecomment-2560196695
protoVersion = '3.25.5'
annotationApiVersion = '1.3.2'
guavaVersion = '32.0.1-jre' // [10.0,)
tallyVersion = '0.13.0' // [0.4.0,)
Expand Down
4 changes: 4 additions & 0 deletions temporal-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ dependencies {
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
testImplementation 'pl.pragmatists:JUnitParams:1.1.1'
testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: "${logbackVersion}"
if (project.hasProperty("edgeDepsTest")) {
testRuntimeOnly "com.google.protobuf:protobuf-java:4.29.3"
testRuntimeOnly "com.google.protobuf:protobuf-java-util:4.29.3"
}
}

// Temporal SDK supports Java 8 or later so to support virtual threads
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ public WorkflowStub newInstance(WorkflowOptions options) {
}

private void checkStarted() {
if (execution.get() == null || execution.get().getWorkflowId() == null) {
if (execution.get() == null) {
throw new IllegalStateException("Null workflowId. Was workflow started?");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,7 @@ public io.temporal.client.schedules.ScheduleSpec protoToScheduleSpec(
Objects.requireNonNull(scheduleSpec);
io.temporal.client.schedules.ScheduleSpec.Builder specBuilder =
io.temporal.client.schedules.ScheduleSpec.newBuilder()
.setTimeZoneName(
scheduleSpec.getTimezoneName() == null ? "" : scheduleSpec.getTimezoneName());
.setTimeZoneName(scheduleSpec.getTimezoneName());

if (scheduleSpec.hasJitter()) {
specBuilder.setJitter(ProtobufTimeUtils.toJavaDuration(scheduleSpec.getJitter()));
Expand Down Expand Up @@ -450,7 +449,7 @@ public io.temporal.client.schedules.ScheduleAction protoToAction(@Nonnull Schedu
wfOptionsBuilder.setWorkflowTaskTimeout(
ProtobufTimeUtils.toJavaDuration(startWfAction.getWorkflowTaskTimeout()));

if (startWfAction.getRetryPolicy() != null) {
if (startWfAction.hasRetryPolicy()) {
wfOptionsBuilder.setRetryOptions(
RetryOptionsUtils.toRetryOptions(startWfAction.getRetryPolicy()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public static WorkflowExecutionHistory fromJson(String serialized) {

private static void checkHistory(History history) {
List<HistoryEvent> events = history.getEventsList();
if (events == null || events.size() == 0) {
if (events.size() == 0) {
throw new IllegalArgumentException("Empty history");
}
HistoryEvent startedEvent = events.get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,8 @@ public static String prettyPrintCommands(Iterable<Command> commands) {
}

/** Pretty prints a proto message. */
@SuppressWarnings("deprecation")
public static String prettyPrintObject(MessageOrBuilder object) {
return TextFormat.printToString(object);
return TextFormat.printer().printToString(object);
}

public static boolean containsEvent(List<HistoryEvent> history, EventType eventType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public void handleWorkflowExecutionUpdated(UpdateMessage updateMessage) {
Message protocolMessage = updateMessage.getMessage();
Request update = protocolMessage.getBody().unpack(Request.class);
Input input = update.getInput();
Optional<Payloads> args = Optional.ofNullable(input.getArgs());
Optional<Payloads> args = Optional.of(input.getArgs());
this.workflow.handleUpdate(
input.getName(),
update.getMeta().getUpdateId(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,7 @@ public WorkflowMetadata getWorkflowMetadata() {
WorkflowMetadata.Builder workflowMetadata = WorkflowMetadata.newBuilder();
WorkflowDefinition.Builder workflowDefinition = WorkflowDefinition.newBuilder();
// Set the workflow type
if (replayContext.getWorkflowType() != null
&& replayContext.getWorkflowType().getName() != null) {
if (replayContext.getWorkflowType() != null) {
workflowDefinition.setType(replayContext.getWorkflowType().getName());
}
// Set built in queries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,8 +434,8 @@ private HistoryEvent newAttributes(EventType type, Object attributes) {
} else if (attributes instanceof Number) {
attributes = newAttributes(type, ((Number) attributes).intValue());
}
if (attributes instanceof com.google.protobuf.GeneratedMessageV3.Builder) {
attributes = ((com.google.protobuf.GeneratedMessageV3.Builder) attributes).build();
if (attributes instanceof com.google.protobuf.Message.Builder) {
attributes = ((com.google.protobuf.Message.Builder) attributes).build();
}
HistoryEvent.Builder result =
HistoryEvent.newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ protected void update(UpdateMessage message, AsyncWorkflowBuilder<Void> builder)
(r) -> {
message.getCallbacks().complete(converter.toPayloads("update result"), null);
});
if (message.getMessage().getProtocolInstanceId() == "message_update") {
if (message.getMessage().getProtocolInstanceId().equals("message_update")) {
builder.add((r) -> stateMachines.completeWorkflow(Optional.empty()));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ public static class TestDynamicUpdateWorkflowImpl implements TestWorkflows.TestW
CompletablePromise<Void> promise = Workflow.newPromise();
List<String> updates = new ArrayList<>();

@Override
public String execute(String input) {
public TestDynamicUpdateWorkflowImpl() {
Workflow.registerListener(
new DynamicUpdateHandler() {
@Override
Expand All @@ -109,6 +108,10 @@ public Object handleExecute(String updateName, EncodedValues args) {
return "update:" + args.get(0, String.class);
}
});
}

@Override
public String execute(String input) {
promise.get();
return updates.stream().reduce("", (a, b) -> a + " " + b);
}
Expand Down
7 changes: 6 additions & 1 deletion temporal-serviceclient/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dependencies {
api "io.grpc:grpc-stub" //Part of WorkflowServiceStubs API
api "io.grpc:grpc-netty-shaded" //Part of WorkflowServiceStubs API, specifically SslContext
api "io.grpc:grpc-services" //Standard gRPC HealthCheck Response class
api "io.grpc:grpc-inprocess" //For the in-process time skipping test server
api "com.google.protobuf:protobuf-java-util:$protoVersion" //proto request and response objects are a part of this module's API
if (JavaVersion.current().isJava9Compatible()) {
//needed for the generated grpc stubs and is not a part of JDK since java 9
Expand All @@ -28,6 +29,10 @@ dependencies {
testImplementation "junit:junit:${junitVersion}"
testImplementation "org.mockito:mockito-core:${mockitoVersion}"

if (project.hasProperty("edgeDepsTest")) {
testRuntimeOnly "com.google.protobuf:protobuf-java:4.29.3"
testRuntimeOnly "com.google.protobuf:protobuf-java-util:4.29.3"
}
testRuntimeOnly "ch.qos.logback:logback-classic:${logbackVersion}"
}

Expand Down Expand Up @@ -72,7 +77,7 @@ protobuf {
// protoc and protoc-gen-grpc-java versions are selected to be compatible
// with the oldest supported versions of protoc and grpc artifacts.
protoc {
artifact = 'com.google.protobuf:protoc:3.10.1' + (System.getProperty("os.arch") == 'aarch64' && System.getProperty("os.name") == 'Mac OS X' ? ':osx-x86_64' : '')
artifact = 'com.google.protobuf:protoc:3.25.5' + (System.getProperty("os.arch") == 'aarch64' && System.getProperty("os.name") == 'Mac OS X' ? ':osx-x86_64' : '')
}
plugins {
grpc {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ public class ProtoUtils {
* This method does exactly what {@link Any#pack(Message)} does. But it doesn't go into reflection
* to fetch the {@code descriptor}, which allows us to avoid a bunch of Graal reflection configs.
*/
public static <T extends GeneratedMessageV3> Any packAny(
T details, Descriptors.Descriptor descriptor) {
public static <T extends Message> Any packAny(T details, Descriptors.Descriptor descriptor) {
return Any.newBuilder()
.setTypeUrl("type.googleapis.com/" + descriptor.getFullName())
.setValue(details.toByteString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.protobuf.GeneratedMessageV3;
import com.google.protobuf.Message;
import io.grpc.Status;
import io.temporal.internal.common.OptionsUtils;
import java.time.Duration;
Expand Down Expand Up @@ -57,7 +57,7 @@ public static RpcRetryOptions getDefaultInstance() {

public static class DoNotRetryItem {
private final Status.Code code;
private final Class<? extends GeneratedMessageV3> detailsClass;
private final Class<? extends Message> detailsClass;

/**
* @param code errors with this code will be considered non retryable. {@link
Expand All @@ -68,7 +68,7 @@ public static class DoNotRetryItem {
* retryable.
*/
public DoNotRetryItem(
@Nonnull Status.Code code, @Nullable Class<? extends GeneratedMessageV3> detailsClass) {
@Nonnull Status.Code code, @Nullable Class<? extends Message> detailsClass) {
this.code = Preconditions.checkNotNull(code, "code");
this.detailsClass = detailsClass;
}
Expand All @@ -77,7 +77,7 @@ public Status.Code getCode() {
return code;
}

public Class<? extends GeneratedMessageV3> getDetailsClass() {
public Class<? extends Message> getDetailsClass() {
return detailsClass;
}
}
Expand Down Expand Up @@ -252,7 +252,7 @@ public Builder setMaximumJitterCoefficient(double maximumJitterCoefficient) {
* with the {@code code} code are non retryable.
*/
public Builder addDoNotRetry(
Status.Code code, @Nullable Class<? extends GeneratedMessageV3> detailsClass) {
Status.Code code, @Nullable Class<? extends Message> detailsClass) {
doNotRetry.add(new DoNotRetryItem(code, detailsClass));
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class StatusUtils {
* @return true if the given failure is found, false otherwise
*/
public static boolean hasFailure(
StatusRuntimeException exception, Class<? extends GeneratedMessageV3> failureType) {
StatusRuntimeException exception, Class<? extends Message> failureType) {
Preconditions.checkNotNull(exception, "exception cannot be null");
com.google.rpc.Status status = StatusProto.fromThrowable(exception);
if (status.getDetailsCount() == 0) {
Expand All @@ -52,7 +52,7 @@ public static boolean hasFailure(
/**
* @return a failure of a given type from the StatusRuntimeException object
*/
public static <T extends GeneratedMessageV3> T getFailure(
public static <T extends Message> T getFailure(
StatusRuntimeException exception, Class<T> failureType) {
Preconditions.checkNotNull(exception, "exception cannot be null");
com.google.rpc.Status status = StatusProto.fromThrowable(exception);
Expand All @@ -72,7 +72,7 @@ public static <T extends GeneratedMessageV3> T getFailure(
}

/** Create StatusRuntimeException with given details. */
public static <T extends GeneratedMessageV3> StatusRuntimeException newException(
public static <T extends Message> StatusRuntimeException newException(
io.grpc.Status status, T details, Descriptors.Descriptor detailsDescriptor) {
Preconditions.checkNotNull(status, "status cannot be null");
Status protoStatus =
Expand Down
2 changes: 1 addition & 1 deletion temporal-test-server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ protobuf {
// protoc and protoc-gen-grpc-java versions are selected to be compatible
// with the oldest supported versions of protoc and grpc artifacts.
protoc {
artifact = 'com.google.protobuf:protoc:3.10.1' + (System.getProperty("os.arch") == 'aarch64' && System.getProperty("os.name") == 'Mac OS X' ? ':osx-x86_64' : '')
artifact = 'com.google.protobuf:protoc:3.25.5' + (System.getProperty("os.arch") == 'aarch64' && System.getProperty("os.name") == 'Mac OS X' ? ':osx-x86_64' : '')
}
plugins {
grpc {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ BackoffInterval getBackoffIntervalInSeconds(
RetryPolicy retryPolicy = getRetryPolicy();
// check if error is non-retryable
List<String> nonRetryableErrorTypes = retryPolicy.getNonRetryableErrorTypesList();
if (nonRetryableErrorTypes != null && errorType.isPresent()) {
if (errorType.isPresent()) {
String type = errorType.get();
for (String err : nonRetryableErrorTypes) {
if (type.equals(err)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3396,7 +3396,6 @@ private void addExecutionSignaledEvent(
RequestContext ctx, SignalWorkflowExecutionRequest signalRequest) {
WorkflowExecutionSignaledEventAttributes.Builder a =
WorkflowExecutionSignaledEventAttributes.newBuilder()
.setInput(startRequest.getInput())
.setIdentity(signalRequest.getIdentity())
.setInput(signalRequest.getInput())
.setSignalName(signalRequest.getSignalName());
Expand All @@ -3412,7 +3411,6 @@ private void addExecutionSignaledByExternalEvent(
RequestContext ctx, SignalExternalWorkflowExecutionCommandAttributes d) {
WorkflowExecutionSignaledEventAttributes.Builder a =
WorkflowExecutionSignaledEventAttributes.newBuilder()
.setInput(startRequest.getInput())
.setInput(d.getInput())
.setSignalName(d.getSignalName());
HistoryEvent executionSignaled =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1348,8 +1348,7 @@ public void signalWithStartWorkflowExecution(
.setWorkflowIdReusePolicy(r.getWorkflowIdReusePolicy())
.setIdentity(r.getIdentity())
.setWorkflowType(r.getWorkflowType())
.setCronSchedule(r.getCronSchedule())
.setRequestId(r.getRequestId());
.setCronSchedule(r.getCronSchedule());
if (r.hasRetryPolicy()) {
startRequest.setRetryPolicy(r.getRetryPolicy());
}
Expand Down
Loading

0 comments on commit 8b17a52

Please sign in to comment.