• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

temporalio / sdk-java / #343

31 Oct 2024 06:31PM UTC coverage: 75.148% (-3.6%) from 78.794%
#343

push

github

web-flow
Fix jacoco coverage (#2304)

5139 of 8240 branches covered (62.37%)

Branch coverage included in aggregate %.

22841 of 28993 relevant lines covered (78.78%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.4
/temporal-sdk/src/main/java/io/temporal/common/metadata/POJOWorkflowImplMetadata.java
1
/*
2
 * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3
 *
4
 * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
 *
6
 * Modifications copyright (C) 2017 Uber Technologies, Inc.
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this material except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *   http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20

21
package io.temporal.common.metadata;
22

23
import com.google.common.collect.ImmutableList;
24
import io.temporal.common.Experimental;
25
import io.temporal.internal.common.env.ReflectionUtils;
26
import java.lang.reflect.Constructor;
27
import java.util.*;
28
import java.util.stream.Collectors;
29
import javax.annotation.Nullable;
30

31
/**
32
 * Rules:
33
 *
34
 * <ul>
35
 *   <li>A workflow implementation must implement at least one non empty interface annotated with
36
 *       WorkflowInterface
37
 *   <li>An interface annotated with WorkflowInterface can extend zero or more interfaces.
38
 *   <li>An interface annotated with WorkflowInterface defines workflow methods for all methods it
39
 *       inherited from interfaces which are not annotated with WorkflowInterface.
40
 *   <li>Each method name can be defined only once across all interfaces annotated with
41
 *       WorkflowInterface. So if annotated interface A has method foo() and an annotated interface
42
 *       B extends A it cannot also declare foo() even with a different signature.
43
 * </ul>
44
 */
45
public final class POJOWorkflowImplMetadata {
46

47
  private static class EqualsByNameType {
48
    private final String name;
49
    private final WorkflowMethodType type;
50

51
    EqualsByNameType(String name, WorkflowMethodType type) {
1✔
52
      this.name = name;
1✔
53
      this.type = type;
1✔
54
    }
1✔
55

56
    @Override
57
    public boolean equals(Object o) {
58
      if (this == o) return true;
1!
59
      if (o == null || getClass() != o.getClass()) return false;
1!
60
      EqualsByNameType that = (EqualsByNameType) o;
1✔
61
      return com.google.common.base.Objects.equal(name, that.name) && type == that.type;
1!
62
    }
63

64
    @Override
65
    public int hashCode() {
66
      return com.google.common.base.Objects.hashCode(name, type);
1✔
67
    }
68
  }
69

70
  private final List<POJOWorkflowInterfaceMetadata> workflowInterfaces;
71
  private final List<POJOWorkflowMethodMetadata> workflowMethods;
72
  private final List<POJOWorkflowMethodMetadata> signalMethods;
73
  private final List<POJOWorkflowMethodMetadata> queryMethods;
74
  private final List<POJOWorkflowMethodMetadata> updateMethods;
75
  private final List<POJOWorkflowMethodMetadata> updateValidatorMethods;
76
  private final Constructor<?> workflowInit;
77

78
  /**
79
   * Create POJOWorkflowImplMetadata for a workflow implementation class. The object must implement
80
   * at least one workflow method. Validates the implementation can be registered.
81
   */
82
  public static POJOWorkflowImplMetadata newInstance(Class<?> implClass) {
83
    return new POJOWorkflowImplMetadata(implClass, false, true);
1✔
84
  }
85

86
  /**
87
   * Create POJOWorkflowImplMetadata for a workflow implementation class. The object must implement
88
   * at least one workflow method. Does not validate the implementation can be registered.
89
   */
90
  public static POJOWorkflowImplMetadata newInstanceForWorkflowFactory(Class<?> implClass) {
91
    return new POJOWorkflowImplMetadata(implClass, false, false);
1✔
92
  }
93

94
  /**
95
   * Create POJOWorkflowImplMetadata for a workflow implementation class. The class may not
96
   * implement any workflow method. This is to be used for classes that implement only query and
97
   * signal methods.
98
   */
99
  public static POJOWorkflowImplMetadata newListenerInstance(Class<?> implClass) {
100
    return new POJOWorkflowImplMetadata(implClass, true, false);
1✔
101
  }
102

103
  private POJOWorkflowImplMetadata(
104
      Class<?> implClass, boolean listener, boolean validateConstructor) {
1✔
105
    if (implClass.isInterface()
1!
106
        || implClass.isPrimitive()
1!
107
        || implClass.isAnnotation()
1!
108
        || implClass.isArray()
1!
109
        || implClass.isEnum()) {
1!
110
      throw new IllegalArgumentException("concrete class expected: " + implClass);
×
111
    }
112

113
    List<POJOWorkflowInterfaceMetadata> workflowInterfaces = new ArrayList<>();
1✔
114
    Map<String, POJOWorkflowMethodMetadata> workflowMethods = new HashMap<>();
1✔
115
    Map<String, POJOWorkflowMethodMetadata> queryMethods = new HashMap<>();
1✔
116
    Map<String, POJOWorkflowMethodMetadata> signalMethods = new HashMap<>();
1✔
117
    Map<String, POJOWorkflowMethodMetadata> updateMethods = new HashMap<>();
1✔
118
    Map<String, POJOWorkflowMethodMetadata> updateValidatorMethods = new HashMap<>();
1✔
119
    Map<EqualsByNameType, POJOWorkflowMethodMetadata> byNameType = new HashMap<>();
1✔
120

121
    // Getting all the top level interfaces instead of the direct ones that Class.getInterfaces()
122
    // returns
123
    Set<Class<?>> interfaces = POJOReflectionUtils.getTopLevelInterfaces(implClass);
1✔
124
    for (Class<?> anInterface : interfaces) {
1✔
125
      POJOWorkflowInterfaceMetadata interfaceMetadata =
1✔
126
          POJOWorkflowInterfaceMetadata.newImplementationInstance(anInterface, listener);
1✔
127
      List<POJOWorkflowMethodMetadata> methods = interfaceMetadata.getMethodsMetadata();
1✔
128
      if (!methods.isEmpty()) {
1✔
129
        workflowInterfaces.add(interfaceMetadata);
1✔
130
      }
131
      for (POJOWorkflowMethodMetadata methodMetadata : methods) {
1✔
132
        EqualsByNameType key =
1✔
133
            new EqualsByNameType(methodMetadata.getName(), methodMetadata.getType());
1✔
134
        POJOWorkflowMethodMetadata registeredMM = byNameType.put(key, methodMetadata);
1✔
135
        if (registeredMM != null
1✔
136
            && !registeredMM.getWorkflowMethod().equals(methodMetadata.getWorkflowMethod())) {
1✔
137
          throw new IllegalArgumentException(
1✔
138
              "Duplicated name of "
139
                  + methodMetadata.getType()
1✔
140
                  + ": \""
141
                  + methodMetadata.getName()
1✔
142
                  + "\" declared at \""
143
                  + registeredMM.getWorkflowMethod()
1✔
144
                  + "\" and \""
145
                  + methodMetadata.getWorkflowMethod()
1✔
146
                  + "\"");
147
        }
148
        switch (methodMetadata.getType()) {
1!
149
          case WORKFLOW:
150
            workflowMethods.put(methodMetadata.getName(), methodMetadata);
1✔
151
            break;
1✔
152
          case SIGNAL:
153
            signalMethods.put(methodMetadata.getName(), methodMetadata);
1✔
154
            break;
1✔
155
          case QUERY:
156
            queryMethods.put(methodMetadata.getName(), methodMetadata);
1✔
157
            break;
1✔
158
          case UPDATE:
159
            updateMethods.put(methodMetadata.getName(), methodMetadata);
1✔
160
            break;
1✔
161
          case UPDATE_VALIDATOR:
162
            updateValidatorMethods.put(methodMetadata.getName(), methodMetadata);
1✔
163
            break;
164
        }
165
      }
1✔
166
    }
1✔
167
    if (byNameType.isEmpty() && !listener) {
1✔
168
      throw new IllegalArgumentException(
1✔
169
          "Class doesn't implement any non empty public interface annotated with @WorkflowInterface: "
170
              + implClass.getName());
1✔
171
    }
172
    this.workflowInterfaces = ImmutableList.copyOf(workflowInterfaces);
1✔
173
    this.workflowMethods = ImmutableList.copyOf(workflowMethods.values());
1✔
174
    this.signalMethods = ImmutableList.copyOf(signalMethods.values());
1✔
175
    this.queryMethods = ImmutableList.copyOf(queryMethods.values());
1✔
176
    this.updateMethods = ImmutableList.copyOf(updateMethods.values());
1✔
177
    this.updateValidatorMethods = ImmutableList.copyOf(updateValidatorMethods.values());
1✔
178
    if (!listener && validateConstructor) {
1✔
179
      this.workflowInit =
1✔
180
          ReflectionUtils.getConstructor(
1✔
181
                  implClass,
182
                  this.workflowMethods.stream()
1✔
183
                      .map(POJOWorkflowMethodMetadata::getWorkflowMethod)
1✔
184
                      .collect(Collectors.toList()))
1✔
185
              .orElse(null);
1✔
186
    } else {
187
      this.workflowInit = null;
1✔
188
    }
189
  }
1✔
190

191
  /** List of workflow interfaces an object implements. */
192
  public List<POJOWorkflowInterfaceMetadata> getWorkflowInterfaces() {
193
    return workflowInterfaces;
1✔
194
  }
195

196
  /** List of workflow methods an object implements across all the workflow interfaces. */
197
  public List<POJOWorkflowMethodMetadata> getWorkflowMethods() {
198
    return workflowMethods;
1✔
199
  }
200

201
  /** List of signal methods an object implements across all the workflow interfaces. */
202
  public List<POJOWorkflowMethodMetadata> getSignalMethods() {
203
    return signalMethods;
1✔
204
  }
205

206
  /** List of query methods an object implements across all the workflow interfaces. */
207
  public List<POJOWorkflowMethodMetadata> getQueryMethods() {
208
    return queryMethods;
1✔
209
  }
210

211
  /** List of update methods an object implements across all the workflow interfaces. */
212
  @Experimental
213
  public List<POJOWorkflowMethodMetadata> getUpdateMethods() {
214
    return updateMethods;
1✔
215
  }
216

217
  /** List of update validator methods an object implements across all the workflow interfaces. */
218
  @Experimental
219
  public List<POJOWorkflowMethodMetadata> getUpdateValidatorMethods() {
220
    return updateValidatorMethods;
1✔
221
  }
222

223
  @Experimental
224
  public @Nullable Constructor<?> getWorkflowInit() {
225
    return workflowInit;
1✔
226
  }
227
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc