Skip to content
This repository was archived by the owner on Dec 13, 2023. It is now read-only.

Commit 34cdf83

Browse files
committed
Merge branch 'main' of github.com:Netflix/conductor into task_limit
� Conflicts: � core/src/test/java/com/netflix/conductor/core/execution/TestDeciderService.java � core/src/test/java/com/netflix/conductor/core/execution/TestWorkflowExecutor.java
2 parents e47a106 + 1061bed commit 34cdf83

File tree

49 files changed

+1044
-803
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1044
-803
lines changed

cassandra-persistence/build.gradle

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/*
2+
* Copyright 2021 Netflix, Inc.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
* <p>
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* <p>
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
114
dependencies {
215
implementation project(':conductor-common')
316
implementation project(':conductor-core')
@@ -11,5 +24,7 @@ dependencies {
1124
testImplementation("org.cassandraunit:cassandra-unit:${revCassandraUnit}") {
1225
exclude group: "com.datastax.cassandra", module: "cassandra-driver-core"
1326
}
27+
1428
testImplementation project(':conductor-core').sourceSets.test.output
29+
testImplementation project(':conductor-common').sourceSets.test.output
1530
}

cassandra-persistence/src/test/java/com/netflix/conductor/cassandra/dao/CassandraDAOTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import com.netflix.conductor.cassandra.dao.CassandraBaseDAO.WorkflowMetadata;
2020
import com.netflix.conductor.cassandra.util.EmbeddedCassandra;
2121
import com.netflix.conductor.cassandra.util.Statements;
22-
import com.netflix.conductor.common.config.ObjectMapperConfiguration;
22+
import com.netflix.conductor.common.config.TestObjectMapperConfiguration;
2323
import com.netflix.conductor.common.metadata.events.EventExecution;
2424
import com.netflix.conductor.common.metadata.events.EventHandler;
2525
import com.netflix.conductor.common.metadata.tasks.Task;
@@ -60,7 +60,7 @@
6060
import static org.mockito.Mockito.mock;
6161
import static org.mockito.Mockito.when;
6262

63-
@ContextConfiguration(classes = {ObjectMapperConfiguration.class})
63+
@ContextConfiguration(classes = {TestObjectMapperConfiguration.class})
6464
@RunWith(SpringRunner.class)
6565
public class CassandraDAOTest {
6666

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2021 Netflix, Inc.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
* <p>
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* <p>
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package com.netflix.conductor.common.config;
15+
16+
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
17+
import org.springframework.context.annotation.Bean;
18+
import org.springframework.context.annotation.Configuration;
19+
20+
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES;
21+
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES;
22+
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
23+
24+
@Configuration
25+
public class ObjectMapperBuilderConfiguration {
26+
27+
/**
28+
* Disable features like {@link ObjectMapperProvider#getObjectMapper()}.
29+
*/
30+
@Bean
31+
public Jackson2ObjectMapperBuilderCustomizer conductorJackson2ObjectMapperBuilderCustomizer() {
32+
return builder -> builder.featuresToDisable(FAIL_ON_UNKNOWN_PROPERTIES,
33+
FAIL_ON_IGNORED_PROPERTIES,
34+
FAIL_ON_NULL_FOR_PRIMITIVES);
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,38 @@
11
/*
2-
* Copyright 2020 Netflix, Inc.
3-
* <p>
4-
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5-
* the License. You may obtain a copy of the License at
6-
* <p>
7-
* http://www.apache.org/licenses/LICENSE-2.0
8-
* <p>
9-
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10-
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11-
* specific language governing permissions and limitations under the License.
2+
* Copyright 2021 Netflix, Inc.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
* <p>
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* <p>
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
1212
*/
1313
package com.netflix.conductor.common.config;
1414

15+
import com.fasterxml.jackson.annotation.JsonInclude;
1516
import com.fasterxml.jackson.databind.ObjectMapper;
16-
import org.springframework.context.annotation.Bean;
1717
import org.springframework.context.annotation.Configuration;
1818

19+
import javax.annotation.PostConstruct;
20+
1921
@Configuration
2022
public class ObjectMapperConfiguration {
2123

22-
@Bean
23-
public ObjectMapper objectMapper() {
24-
return new ObjectMapperProvider().getObjectMapper();
24+
private final ObjectMapper objectMapper;
25+
26+
public ObjectMapperConfiguration(ObjectMapper objectMapper) {
27+
this.objectMapper = objectMapper;
28+
}
29+
30+
/**
31+
* Set default property inclusion like {@link ObjectMapperProvider#getObjectMapper()}.
32+
*/
33+
@PostConstruct
34+
public void customizeDefaultObjectMapper() {
35+
objectMapper.setDefaultPropertyInclusion(
36+
JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.ALWAYS));
2537
}
2638
}

common/src/main/java/com/netflix/conductor/common/config/ObjectMapperProvider.java

+27-125
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,42 @@
11
/*
2-
* Copyright 2020 Netflix, Inc.
3-
* <p>
4-
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5-
* the License. You may obtain a copy of the License at
6-
* <p>
7-
* http://www.apache.org/licenses/LICENSE-2.0
8-
* <p>
9-
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10-
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11-
* specific language governing permissions and limitations under the License.
2+
* Copyright 2021 Netflix, Inc.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
* <p>
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* <p>
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
1212
*/
1313
package com.netflix.conductor.common.config;
1414

1515
import com.fasterxml.jackson.annotation.JsonInclude;
16-
import com.fasterxml.jackson.core.JsonGenerator;
17-
import com.fasterxml.jackson.core.JsonParser;
18-
import com.fasterxml.jackson.databind.DeserializationContext;
1916
import com.fasterxml.jackson.databind.DeserializationFeature;
20-
import com.fasterxml.jackson.databind.JsonDeserializer;
21-
import com.fasterxml.jackson.databind.JsonNode;
22-
import com.fasterxml.jackson.databind.JsonSerializer;
2317
import com.fasterxml.jackson.databind.ObjectMapper;
24-
import com.fasterxml.jackson.databind.SerializerProvider;
25-
import com.fasterxml.jackson.databind.module.SimpleModule;
26-
import com.google.protobuf.Any;
27-
import com.google.protobuf.ByteString;
28-
import com.google.protobuf.Message;
29-
30-
import java.io.IOException;
18+
import com.netflix.conductor.common.jackson.JsonProtoModule;
3119

20+
/**
21+
* A Factory class for creating a customized {@link ObjectMapper}. This is only used by the
22+
* conductor-client module and tests that rely on {@link ObjectMapper}.
23+
* See TestObjectMapperConfiguration.
24+
*/
3225
public class ObjectMapperProvider {
3326

3427
/**
35-
* JsonProtoModule can be registered into an {@link ObjectMapper} to enable the serialization and deserialization of
36-
* ProtoBuf objects from/to JSON.
37-
* <p>
38-
* Right now this module only provides (de)serialization for the {@link Any} ProtoBuf type, as this is the only
39-
* ProtoBuf object which we're currently exposing through the REST API.
40-
* <p>
41-
* {@see AnySerializer}, {@see AnyDeserializer}
28+
* The customizations in this method are configured using {@link org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration}
29+
*
30+
* Customizations are spread across,
31+
* 1. {@link ObjectMapperBuilderConfiguration}
32+
* 2. {@link ObjectMapperConfiguration}
33+
* 3. {@link JsonProtoModule}
34+
*
35+
* IMPORTANT: Changes in this method need to be also performed in the default {@link ObjectMapper}
36+
* that Spring Boot creates.
37+
*
38+
* @see org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
4239
*/
43-
private static class JsonProtoModule extends SimpleModule {
44-
45-
private final static String JSON_TYPE = "@type";
46-
private final static String JSON_VALUE = "@value";
47-
48-
/**
49-
* AnySerializer converts a ProtoBuf {@link Any} object into its JSON representation.
50-
* <p>
51-
* This is <b>not</b> a canonical ProtoBuf JSON representation. Let us explain what we're trying to accomplish
52-
* here:
53-
* <p>
54-
* The {@link Any} ProtoBuf message is a type in the PB standard library that can store any other arbitrary
55-
* ProtoBuf message in a type-safe way, even when the server has no knowledge of the schema of the stored
56-
* message.
57-
* <p>
58-
* It accomplishes this by storing a tuple of information: an URL-like type declaration for the stored message,
59-
* and the serialized binary encoding of the stored message itself. Language specific implementations of
60-
* ProtoBuf provide helper methods to encode and decode arbitrary messages into an {@link Any} object ({@link
61-
* Any#pack(Message)} in Java).
62-
* <p>
63-
* We want to expose these {@link Any} objects in the REST API because they've been introduced as part of the
64-
* new GRPC interface to Conductor, but unfortunately we cannot encode them using their canonical ProtoBuf JSON
65-
* encoding. According to the docs:
66-
* <p>
67-
* The JSON representation of an `Any` value uses the regular representation of the deserialized, embedded
68-
* message, with an additional field `@type` which contains the type URL. Example:
69-
* <p>
70-
* package google.profile; message Person { string first_name = 1; string last_name = 2; } { "@type":
71-
* "type.googleapis.com/google.profile.Person", "firstName": <string>, "lastName": <string> }
72-
* <p>
73-
* In order to accomplish this representation, the PB-JSON encoder needs to have knowledge of all the ProtoBuf
74-
* messages that could be serialized inside the {@link Any} message. This is not possible to accomplish inside
75-
* the Conductor server, which is simply passing through arbitrary payloads from/to clients.
76-
* <p>
77-
* Consequently, to actually expose the Message through the REST API, we must create a custom encoding that
78-
* contains the raw data of the serialized message, as we are not able to deserialize it on the server. We
79-
* simply return a dictionary with '@type' and '@value' keys, where '@type' is identical to the canonical
80-
* representation, but '@value' contains a base64 encoded string with the binary data of the serialized
81-
* message.
82-
* <p>
83-
* Since all the provided Conductor clients are required to know this encoding, it's always possible to re-build
84-
* the original {@link Any} message regardless of the client's language.
85-
* <p>
86-
* {@see AnyDeserializer}
87-
*/
88-
@SuppressWarnings("InnerClassMayBeStatic")
89-
protected class AnySerializer extends JsonSerializer<Any> {
90-
91-
@Override
92-
public void serialize(Any value, JsonGenerator jgen, SerializerProvider provider)
93-
throws IOException {
94-
jgen.writeStartObject();
95-
jgen.writeStringField(JSON_TYPE, value.getTypeUrl());
96-
jgen.writeBinaryField(JSON_VALUE, value.getValue().toByteArray());
97-
jgen.writeEndObject();
98-
}
99-
}
100-
101-
/**
102-
* AnyDeserializer converts the custom JSON representation of an {@link Any} value into its original form.
103-
* <p>
104-
* {@see AnySerializer} for details on this representation.
105-
*/
106-
@SuppressWarnings("InnerClassMayBeStatic")
107-
protected class AnyDeserializer extends JsonDeserializer<Any> {
108-
109-
@Override
110-
public Any deserialize(JsonParser p, DeserializationContext ctxt)
111-
throws IOException {
112-
JsonNode root = p.getCodec().readTree(p);
113-
JsonNode type = root.get(JSON_TYPE);
114-
JsonNode value = root.get(JSON_VALUE);
115-
116-
if (type == null || !type.isTextual()) {
117-
ctxt.reportMappingException("invalid '@type' field when deserializing ProtoBuf Any object");
118-
}
119-
120-
if (value == null || !value.isTextual()) {
121-
ctxt.reportMappingException("invalid '@value' field when deserializing ProtoBuf Any object");
122-
}
123-
124-
return Any.newBuilder()
125-
.setTypeUrl(type.textValue())
126-
.setValue(ByteString.copyFrom(value.binaryValue()))
127-
.build();
128-
}
129-
}
130-
131-
public JsonProtoModule() {
132-
super("ConductorJsonProtoModule");
133-
addSerializer(Any.class, new AnySerializer());
134-
addDeserializer(Any.class, new AnyDeserializer());
135-
}
136-
}
137-
13840
public ObjectMapper getObjectMapper() {
13941
final ObjectMapper objectMapper = new ObjectMapper();
14042
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

0 commit comments

Comments
 (0)