Skip to content

Commit 5a37693

Browse files
committed
Fix #709 Handling AllOf
Signed-off-by: fjtirado <ftirados@redhat.com>
1 parent 75fbd15 commit 5a37693

File tree

7 files changed

+160
-60
lines changed

7 files changed

+160
-60
lines changed

annotations/src/main/java/io/serverlessworkflow/annotations/Union.java renamed to annotations/src/main/java/io/serverlessworkflow/annotations/ExclusiveUnion.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@
2323

2424
@Retention(RUNTIME)
2525
@Target(ElementType.TYPE)
26-
public @interface Union {
26+
public @interface ExclusiveUnion {
2727
Class<?>[] value();
2828
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.annotations;
17+
18+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
19+
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.Target;
23+
24+
@Retention(RUNTIME)
25+
@Target(ElementType.TYPE)
26+
public @interface InclusiveUnion {
27+
Class<?>[] value();
28+
}

api/src/test/java/io/serverlessworkflow/api/ApiTest.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,31 @@ void testCallFunctionAPIWithoutArguments() throws IOException {
6666
CallTask callTask = task.getCallTask();
6767
assertThat(callTask).isNotNull();
6868
assertThat(callTask.get()).isInstanceOf(CallFunction.class);
69-
if (callTask.get() instanceof CallFunction) {
70-
CallFunction functionCall = callTask.getCallFunction();
71-
assertThat(functionCall).isNotNull();
72-
assertThat(callTask.getCallAsyncAPI()).isNull();
73-
assertThat(functionCall.getWith()).isNull();
74-
}
69+
CallFunction functionCall = callTask.getCallFunction();
70+
assertThat(functionCall).isNotNull();
71+
assertThat(callTask.getCallAsyncAPI()).isNull();
72+
assertThat(functionCall.getWith()).isNull();
73+
}
74+
75+
@Test
76+
void testOauth2Auth() throws IOException {
77+
Workflow workflow = readWorkflowFromClasspath("features/authentication-oauth2.yaml");
78+
assertThat(workflow.getDo()).isNotEmpty();
79+
assertThat(workflow.getDo().get(0).getName()).isNotNull();
80+
assertThat(workflow.getDo().get(0).getTask()).isNotNull();
81+
Task task = workflow.getDo().get(0).getTask();
82+
CallTask callTask = task.getCallTask();
83+
assertThat(callTask).isNotNull();
84+
assertThat(callTask.get()).isInstanceOf(CallHTTP.class);
85+
CallHTTP httpCall = callTask.getCallHTTP();
86+
assertThat(
87+
httpCall
88+
.getWith()
89+
.getEndpoint()
90+
.getEndpointConfiguration()
91+
.getAuthentication()
92+
.getAuthenticationPolicy()
93+
.getOAuth2AuthenticationPolicy())
94+
.isNotNull();
7595
}
7696
}

generators/jackson/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import com.fasterxml.jackson.annotation.JsonAnySetter;
2020
import com.fasterxml.jackson.annotation.JsonCreator;
2121
import com.fasterxml.jackson.annotation.JsonIgnore;
22+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
23+
import com.fasterxml.jackson.annotation.JsonUnwrapped;
2224
import com.fasterxml.jackson.annotation.JsonValue;
2325
import com.fasterxml.jackson.databind.Module.SetupContext;
2426
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -43,10 +45,11 @@
4345
import io.github.classgraph.TypeArgument;
4446
import io.github.classgraph.TypeSignature;
4547
import io.serverlessworkflow.annotations.AdditionalProperties;
48+
import io.serverlessworkflow.annotations.ExclusiveUnion;
49+
import io.serverlessworkflow.annotations.InclusiveUnion;
4650
import io.serverlessworkflow.annotations.Item;
4751
import io.serverlessworkflow.annotations.ItemKey;
4852
import io.serverlessworkflow.annotations.ItemValue;
49-
import io.serverlessworkflow.annotations.Union;
5053
import java.io.File;
5154
import java.io.IOException;
5255
import java.io.PrintStream;
@@ -110,7 +113,8 @@ public void execute() throws MojoExecutionException, MojoFailureException {
110113
._class("JacksonMixInModule")
111114
._extends(SimpleModule.class)
112115
.method(JMod.PUBLIC, codeModel.VOID, SETUP_METHOD);
113-
processAnnotatedClasses(result, Union.class, this::buildUnionMixIn);
116+
processAnnotatedClasses(result, ExclusiveUnion.class, this::buildExclusiveUnionMixIn);
117+
processAnnotatedClasses(result, InclusiveUnion.class, this::buildInclusiveUnionMixIn);
114118
processAnnotatedClasses(result, AdditionalProperties.class, this::buildAdditionalPropsMixIn);
115119
processAnnotatedClasses(result, Item.class, this::buildItemMixIn);
116120
processAnnotatedClasses(result.getAllEnums(), this::buildEnumMixIn);
@@ -188,7 +192,7 @@ private void buildItemMixIn(ClassInfo classInfo, JDefinedClass mixClass)
188192
GeneratorUtils.generateDeserializer(rootPackage, relClass, getReturnType(valueMethod)));
189193
}
190194

191-
private void buildUnionMixIn(ClassInfo unionClassInfo, JDefinedClass unionMixClass)
195+
private void buildExclusiveUnionMixIn(ClassInfo unionClassInfo, JDefinedClass unionMixClass)
192196
throws JClassAlreadyExistsException {
193197
JClass unionClass = codeModel.ref(unionClassInfo.getName());
194198
unionMixClass
@@ -199,13 +203,25 @@ private void buildUnionMixIn(ClassInfo unionClassInfo, JDefinedClass unionMixCla
199203
.param(
200204
"using",
201205
GeneratorUtils.generateDeserializer(
202-
rootPackage, unionClass, getUnionClasses(unionClassInfo)));
206+
rootPackage, unionClass, getUnionClasses(ExclusiveUnion.class, unionClassInfo)));
207+
}
208+
209+
private void buildInclusiveUnionMixIn(ClassInfo unionClassInfo, JDefinedClass unionMixClass)
210+
throws JClassAlreadyExistsException {
211+
Collection<JClass> unionClasses = getUnionClasses(InclusiveUnion.class, unionClassInfo);
212+
for (MethodInfo methodInfo : unionClassInfo.getMethodInfo()) {
213+
JClass typeClass = getReturnType(methodInfo);
214+
if (unionClasses.contains(typeClass)) {
215+
JMethod method = unionMixClass.method(JMod.ABSTRACT, typeClass, methodInfo.getName());
216+
method.annotate(JsonUnwrapped.class);
217+
method.annotate(JsonIgnoreProperties.class).param("ignoreUnknown", true);
218+
}
219+
}
203220
}
204221

205222
private void buildEnumMixIn(ClassInfo classInfo, JDefinedClass mixClass)
206223
throws JClassAlreadyExistsException {
207224
mixClass.method(JMod.ABSTRACT, String.class, "value").annotate(JsonValue.class);
208-
209225
JMethod staticMethod =
210226
mixClass.method(JMod.STATIC, codeModel.ref(classInfo.getName()), "fromValue");
211227
staticMethod.param(String.class, "value");
@@ -217,8 +233,9 @@ private JDefinedClass createMixInClass(ClassInfo classInfo) throws JClassAlready
217233
return rootPackage._class(JMod.ABSTRACT, classInfo.getSimpleName() + "MixIn");
218234
}
219235

220-
private Collection<JClass> getUnionClasses(ClassInfo unionClassInfo) {
221-
AnnotationInfo info = unionClassInfo.getAnnotationInfoRepeatable(Union.class).get(0);
236+
private Collection<JClass> getUnionClasses(
237+
Class<? extends Annotation> annotation, ClassInfo unionClassInfo) {
238+
AnnotationInfo info = unionClassInfo.getAnnotationInfoRepeatable(annotation).get(0);
222239
Object[] unionClasses = (Object[]) info.getParameterValues().getValue("value");
223240
return Stream.of(unionClasses)
224241
.map(AnnotationClassRef.class::cast)

generators/types/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import com.fasterxml.jackson.databind.JsonNode;
1919
import com.fasterxml.jackson.databind.node.ArrayNode;
20-
import com.sun.codemodel.JAnnotationArrayMember;
2120
import com.sun.codemodel.JBlock;
2221
import com.sun.codemodel.JClass;
2322
import com.sun.codemodel.JClassAlreadyExistsException;
@@ -32,9 +31,10 @@
3231
import com.sun.codemodel.JPackage;
3332
import com.sun.codemodel.JType;
3433
import com.sun.codemodel.JVar;
34+
import io.serverlessworkflow.annotations.ExclusiveUnion;
35+
import io.serverlessworkflow.annotations.InclusiveUnion;
3536
import io.serverlessworkflow.annotations.OneOfSetter;
3637
import io.serverlessworkflow.annotations.OneOfValueProvider;
37-
import io.serverlessworkflow.annotations.Union;
3838
import jakarta.validation.ConstraintViolationException;
3939
import java.io.UnsupportedEncodingException;
4040
import java.net.URI;
@@ -62,9 +62,9 @@ class AllAnyOneOfSchemaRule extends SchemaRule {
6262
this.ruleFactory = ruleFactory;
6363
}
6464

65-
private static final String REF = "$ref";
65+
static final String REF = "$ref";
6666
private static final String TITLE = "title";
67-
private static final String PATTERN = "pattern";
67+
static final String PATTERN = "pattern";
6868

6969
private enum Format {
7070
URI_TEMPLATE("^[A-Za-z][A-Za-z0-9+\\-.]*://.*");
@@ -91,46 +91,6 @@ String pattern() {
9191
}
9292
}
9393

94-
private static class JTypeWrapper implements Comparable<JTypeWrapper> {
95-
96-
private final JType type;
97-
private final JsonNode node;
98-
99-
public JTypeWrapper(JType type, JsonNode node) {
100-
this.type = type;
101-
this.node = node;
102-
}
103-
104-
public JType getType() {
105-
return type;
106-
}
107-
108-
public JsonNode getNode() {
109-
return node;
110-
}
111-
112-
@Override
113-
public int compareTo(JTypeWrapper other) {
114-
return typeToNumber() - other.typeToNumber();
115-
}
116-
117-
private int typeToNumber() {
118-
if (type.name().equals("Object")) {
119-
return 6;
120-
} else if (type.name().equals("String")) {
121-
return node.has(PATTERN) || node.has(REF) ? 4 : 5;
122-
} else if (type.isPrimitive()) {
123-
return 3;
124-
} else if (type.isReference()) {
125-
return 2;
126-
} else if (type.isArray()) {
127-
return 1;
128-
} else {
129-
return 0;
130-
}
131-
}
132-
}
133-
13494
@Override
13595
public JType apply(
13696
String nodeName,
@@ -303,6 +263,9 @@ private Schema childSchema(Schema parentSchema, String prefix, int pos) {
303263

304264
private JDefinedClass populateAllOf(
305265
Schema parentSchema, JDefinedClass definedClass, Collection<JTypeWrapper> allOfTypes) {
266+
if (!allOfTypes.isEmpty()) {
267+
GeneratorUtils.annotateCollection(definedClass, InclusiveUnion.class, allOfTypes);
268+
}
306269
return wrapAll(parentSchema, definedClass, Optional.empty(), allOfTypes, Optional.empty());
307270
}
308271

@@ -321,8 +284,7 @@ private JDefinedClass populateOneOf(
321284
definedClass._implements(
322285
definedClass.owner().ref(OneOfValueProvider.class).narrow(valueField.type()));
323286
GeneratorUtils.implementInterface(definedClass, valueField);
324-
JAnnotationArrayMember unionAnnotation = definedClass.annotate(Union.class).paramArray("value");
325-
oneOfTypes.forEach(t -> unionAnnotation.param(t.getType()));
287+
GeneratorUtils.annotateCollection(definedClass, ExclusiveUnion.class, oneOfTypes);
326288
return wrapAll(parentSchema, definedClass, commonType, oneOfTypes, Optional.of(valueField));
327289
}
328290

generators/types/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
*/
1616
package io.serverlessworkflow.generator;
1717

18+
import com.sun.codemodel.JAnnotationArrayMember;
1819
import com.sun.codemodel.JDefinedClass;
1920
import com.sun.codemodel.JFieldVar;
2021
import com.sun.codemodel.JMethod;
2122
import com.sun.codemodel.JMod;
23+
import java.lang.annotation.Annotation;
24+
import java.util.Collection;
2225
import org.jsonschema2pojo.util.NameHelper;
2326

2427
public class GeneratorUtils {
@@ -41,5 +44,13 @@ public static JMethod getterMethod(
4144
return method;
4245
}
4346

47+
public static void annotateCollection(
48+
JDefinedClass definedClass,
49+
Class<? extends Annotation> annotation,
50+
Collection<JTypeWrapper> types) {
51+
JAnnotationArrayMember unionAnnotation = definedClass.annotate(annotation).paramArray("value");
52+
types.forEach(t -> unionAnnotation.param(t.getType()));
53+
}
54+
4455
private GeneratorUtils() {}
4556
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.generator;
17+
18+
import static io.serverlessworkflow.generator.AllAnyOneOfSchemaRule.PATTERN;
19+
import static io.serverlessworkflow.generator.AllAnyOneOfSchemaRule.REF;
20+
21+
import com.fasterxml.jackson.databind.JsonNode;
22+
import com.sun.codemodel.JType;
23+
24+
class JTypeWrapper implements Comparable<JTypeWrapper> {
25+
26+
private final JType type;
27+
private final JsonNode node;
28+
29+
public JTypeWrapper(JType type, JsonNode node) {
30+
this.type = type;
31+
this.node = node;
32+
}
33+
34+
public JType getType() {
35+
return type;
36+
}
37+
38+
public JsonNode getNode() {
39+
return node;
40+
}
41+
42+
@Override
43+
public int compareTo(JTypeWrapper other) {
44+
return typeToNumber() - other.typeToNumber();
45+
}
46+
47+
private int typeToNumber() {
48+
if (type.name().equals("Object")) {
49+
return 6;
50+
} else if (type.name().equals("String")) {
51+
return node.has(PATTERN) || node.has(REF) ? 4 : 5;
52+
} else if (type.isPrimitive()) {
53+
return 3;
54+
} else if (type.isReference()) {
55+
return 2;
56+
} else if (type.isArray()) {
57+
return 1;
58+
} else {
59+
return 0;
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)