This repository has been archived by the owner on Jan 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- updated README and tests to use ImmutableRecordCopier
- Loading branch information
Showing
10 changed files
with
439 additions
and
236 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
198 changes: 198 additions & 0 deletions
198
src/main/java/io/zeebe/protocol/immutables/ImmutableRecordCopier.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
/* | ||
* Copyright © 2020 camunda services GmbH (info@camunda.com) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package io.zeebe.protocol.immutables; | ||
|
||
import io.zeebe.protocol.immutables.record.ImmutableDeployedWorkflow; | ||
import io.zeebe.protocol.immutables.record.ImmutableDeploymentRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableDeploymentResource; | ||
import io.zeebe.protocol.immutables.record.ImmutableErrorRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableIncidentRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableJobBatchRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableJobRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableMessageRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableMessageStartEventSubscriptionRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableMessageSubscriptionRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableRecord; | ||
import io.zeebe.protocol.immutables.record.ImmutableRecord.Builder; | ||
import io.zeebe.protocol.immutables.record.ImmutableTimerRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableVariableDocumentRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableVariableRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableWorkflowInstanceCreationRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableWorkflowInstanceRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableWorkflowInstanceResultRecordValue; | ||
import io.zeebe.protocol.immutables.record.ImmutableWorkflowInstanceSubscriptionRecordValue; | ||
import io.zeebe.protocol.record.Record; | ||
import io.zeebe.protocol.record.RecordValue; | ||
import io.zeebe.protocol.record.ValueType; | ||
import io.zeebe.protocol.record.value.DeploymentRecordValue; | ||
import io.zeebe.protocol.record.value.ErrorRecordValue; | ||
import io.zeebe.protocol.record.value.IncidentRecordValue; | ||
import io.zeebe.protocol.record.value.JobBatchRecordValue; | ||
import io.zeebe.protocol.record.value.JobRecordValue; | ||
import io.zeebe.protocol.record.value.MessageRecordValue; | ||
import io.zeebe.protocol.record.value.MessageStartEventSubscriptionRecordValue; | ||
import io.zeebe.protocol.record.value.MessageSubscriptionRecordValue; | ||
import io.zeebe.protocol.record.value.TimerRecordValue; | ||
import io.zeebe.protocol.record.value.VariableDocumentRecordValue; | ||
import io.zeebe.protocol.record.value.VariableRecordValue; | ||
import io.zeebe.protocol.record.value.WorkflowInstanceCreationRecordValue; | ||
import io.zeebe.protocol.record.value.WorkflowInstanceRecordValue; | ||
import io.zeebe.protocol.record.value.WorkflowInstanceResultRecordValue; | ||
import io.zeebe.protocol.record.value.WorkflowInstanceSubscriptionRecordValue; | ||
import io.zeebe.protocol.record.value.deployment.DeployedWorkflow; | ||
import io.zeebe.protocol.record.value.deployment.DeploymentResource; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
/** | ||
* Utility class to perform deep copy of any {@link Record<>} implementation to an equivalent {@link | ||
* ImmutableRecord<>} implementation. | ||
* | ||
* <p>This is necessary as by default the {@code copyOf()} methods generated by the library perform | ||
* only shallow copies to some extent - that is, they will correctly detect when a member has an | ||
* equivalent {@code Immutable*} type, but not when said member is a collection or a container. | ||
* | ||
* <p>If you want to perform deep copies, for example to compare two implementations, you can use | ||
* the methods below. | ||
*/ | ||
public final class ImmutableRecordCopier { | ||
|
||
private ImmutableRecordCopier() {} | ||
|
||
@SuppressWarnings("unchecked") | ||
public static <T extends RecordValue, U extends T> ImmutableRecord<U> deepCopyOfRecord( | ||
final Record<T> record) { | ||
final U value = (U) deepCopyOfRecordValue(record.getValueType(), record.getValue()); | ||
final Builder<T> originalBuilder = ImmutableRecord.<T>builder().from(record); | ||
final Builder<U> convertedBuilder = (Builder<U>) originalBuilder; | ||
|
||
return convertedBuilder.value(value).build(); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public static <T extends RecordValue, U extends T> T deepCopyOfRecordValue( | ||
final ValueType type, final T value) { | ||
switch (type) { | ||
case JOB: | ||
return (U) ImmutableJobRecordValue.builder().from((JobRecordValue) value).build(); | ||
case DEPLOYMENT: | ||
return (U) deepCopyOfDeploymentRecordValue((DeploymentRecordValue) value); | ||
case WORKFLOW_INSTANCE: | ||
return (U) | ||
ImmutableWorkflowInstanceRecordValue.builder() | ||
.from((WorkflowInstanceRecordValue) value) | ||
.build(); | ||
case INCIDENT: | ||
return (U) ImmutableIncidentRecordValue.builder().from((IncidentRecordValue) value).build(); | ||
case MESSAGE: | ||
return (U) ImmutableMessageRecordValue.builder().from((MessageRecordValue) value).build(); | ||
case MESSAGE_SUBSCRIPTION: | ||
return (U) | ||
ImmutableMessageSubscriptionRecordValue.builder() | ||
.from((MessageSubscriptionRecordValue) value) | ||
.build(); | ||
case WORKFLOW_INSTANCE_SUBSCRIPTION: | ||
return (U) | ||
ImmutableWorkflowInstanceSubscriptionRecordValue.builder() | ||
.from((WorkflowInstanceSubscriptionRecordValue) value) | ||
.build(); | ||
case JOB_BATCH: | ||
return (U) deepCopyOfJobBatchRecordValue((JobBatchRecordValue) value); | ||
case TIMER: | ||
return (U) ImmutableTimerRecordValue.builder().from((TimerRecordValue) value).build(); | ||
case MESSAGE_START_EVENT_SUBSCRIPTION: | ||
return (U) | ||
ImmutableMessageStartEventSubscriptionRecordValue.builder() | ||
.from((MessageStartEventSubscriptionRecordValue) value) | ||
.build(); | ||
case VARIABLE: | ||
return (U) ImmutableVariableRecordValue.builder().from((VariableRecordValue) value).build(); | ||
case VARIABLE_DOCUMENT: | ||
return (U) | ||
ImmutableVariableDocumentRecordValue.builder() | ||
.from((VariableDocumentRecordValue) value) | ||
.build(); | ||
case WORKFLOW_INSTANCE_CREATION: | ||
return (U) | ||
ImmutableWorkflowInstanceCreationRecordValue.builder() | ||
.from((WorkflowInstanceCreationRecordValue) value) | ||
.build(); | ||
case ERROR: | ||
return (U) ImmutableErrorRecordValue.builder().from((ErrorRecordValue) value).build(); | ||
case WORKFLOW_INSTANCE_RESULT: | ||
return (U) | ||
ImmutableWorkflowInstanceResultRecordValue.builder() | ||
.from((WorkflowInstanceResultRecordValue) value) | ||
.build(); | ||
case SBE_UNKNOWN: | ||
case NULL_VAL: | ||
default: | ||
throw new IllegalArgumentException("Unknown value type " + type); | ||
} | ||
} | ||
|
||
private static ImmutableDeploymentRecordValue deepCopyOfDeploymentRecordValue( | ||
final DeploymentRecordValue value) { | ||
final List<DeployedWorkflow> workflows = new ArrayList<>(); | ||
final List<DeploymentResource> resources = new ArrayList<>(); | ||
|
||
for (final DeployedWorkflow workflow : value.getDeployedWorkflows()) { | ||
final ImmutableDeployedWorkflow immutableWorkflow; | ||
if (workflow instanceof ImmutableDeployedWorkflow) { | ||
immutableWorkflow = (ImmutableDeployedWorkflow) workflow; | ||
} else { | ||
immutableWorkflow = ImmutableDeployedWorkflow.builder().from(workflow).build(); | ||
} | ||
|
||
workflows.add(immutableWorkflow); | ||
} | ||
|
||
for (final DeploymentResource resource : value.getResources()) { | ||
final ImmutableDeploymentResource immutableResource; | ||
if (resource instanceof ImmutableDeploymentResource) { | ||
immutableResource = (ImmutableDeploymentResource) resource; | ||
} else { | ||
immutableResource = ImmutableDeploymentResource.builder().from(resource).build(); | ||
} | ||
|
||
resources.add(immutableResource); | ||
} | ||
|
||
return ImmutableDeploymentRecordValue.builder() | ||
.from(value) | ||
.resources(resources) | ||
.deployedWorkflows(workflows) | ||
.build(); | ||
} | ||
|
||
private static ImmutableJobBatchRecordValue deepCopyOfJobBatchRecordValue( | ||
final JobBatchRecordValue value) { | ||
final List<JobRecordValue> jobs = new ArrayList<>(); | ||
|
||
for (final JobRecordValue job : value.getJobs()) { | ||
final ImmutableJobRecordValue immutableJob; | ||
if (job instanceof ImmutableJobRecordValue) { | ||
immutableJob = (ImmutableJobRecordValue) job; | ||
} else { | ||
immutableJob = ImmutableJobRecordValue.builder().from(job).build(); | ||
} | ||
|
||
jobs.add(immutableJob); | ||
} | ||
|
||
return ImmutableJobBatchRecordValue.builder().from(value).jobs(jobs).build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
src/test/java/io/zeebe/protocol/immutables/ImmutableRecordCopierTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Copyright © 2020 camunda services GmbH (info@camunda.com) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package io.zeebe.protocol.immutables; | ||
|
||
import static org.assertj.core.api.Assertions.assertThatCode; | ||
|
||
import io.zeebe.protocol.record.ValueType; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.EnumSource; | ||
import org.junit.jupiter.params.provider.EnumSource.Mode; | ||
|
||
final class ImmutableRecordCopierTest { | ||
|
||
/** | ||
* This test checks that every known record value type is handled by the {@link | ||
* ImmutableRecordCopier}, and should fail if it isn't. This is a smoke test when updating Zeebe | ||
* versions to detect new {@link io.zeebe.protocol.record.ValueType} instances. | ||
*/ | ||
@EnumSource( | ||
value = ValueType.class, | ||
names = {"NULL_VAL", "SBE_UNKNOWN"}, | ||
mode = Mode.EXCLUDE) | ||
@ParameterizedTest | ||
void shouldHandleEveryKnownValueType(final ValueType type) { | ||
assertThatCode(() -> ImmutableRecordCopier.deepCopyOfRecordValue(type, null)) | ||
.isNotInstanceOf(IllegalArgumentException.class); | ||
} | ||
} |
Oops, something went wrong.