diff --git a/experimental/model/pom.xml b/experimental/model/pom.xml index 6777d9e2b..ca71d249a 100644 --- a/experimental/model/pom.xml +++ b/experimental/model/pom.xml @@ -8,9 +8,21 @@ serverlessworkflow-experimental-model Serverless Workflow :: Experimental :: Model - - io.serverlessworkflow - serverlessworkflow-impl-core - + + io.serverlessworkflow + serverlessworkflow-impl-core + + + org.junit.jupiter + junit-jupiter-engine + + + org.assertj + assertj-core + + + ch.qos.logback + logback-classic + \ No newline at end of file diff --git a/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/JavaModel.java b/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/JavaModel.java index a0a13c0f4..506663b62 100644 --- a/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/JavaModel.java +++ b/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/JavaModel.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -104,4 +105,18 @@ protected Optional convert(Class clazz) { ? Optional.of(clazz.cast(object)) : Optional.empty(); } + + @Override + public int hashCode() { + return Objects.hash(object); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + JavaModel other = (JavaModel) obj; + return Objects.equals(object, other.object); + } } diff --git a/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/JavaModelMarshaller.java b/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/JavaModelMarshaller.java new file mode 100644 index 000000000..bf279f8bf --- /dev/null +++ b/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/JavaModelMarshaller.java @@ -0,0 +1,43 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.model.func; + +import io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller; +import io.serverlessworkflow.impl.marshaller.WorkflowInputBuffer; +import io.serverlessworkflow.impl.marshaller.WorkflowOutputBuffer; + +public class JavaModelMarshaller implements CustomObjectMarshaller { + + @Override + public void write(WorkflowOutputBuffer buffer, JavaModel object) { + buffer.writeObject(object.asJavaObject()); + } + + @Override + public JavaModel read(WorkflowInputBuffer buffer, Class clazz) { + return new JavaModel(buffer.readObject()); + } + + @Override + public Class getObjectClass() { + return JavaModel.class; + } + + @Override + public int priority() { + return Integer.MAX_VALUE; + } +} diff --git a/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/SerializableObjectMarshaller.java b/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/SerializableObjectMarshaller.java new file mode 100644 index 000000000..33eeeea8c --- /dev/null +++ b/experimental/model/src/main/java/io/serverlessworkflow/impl/model/func/SerializableObjectMarshaller.java @@ -0,0 +1,63 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.model.func; + +import io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller; +import io.serverlessworkflow.impl.marshaller.WorkflowInputBuffer; +import io.serverlessworkflow.impl.marshaller.WorkflowOutputBuffer; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.io.UncheckedIOException; + +public class SerializableObjectMarshaller implements CustomObjectMarshaller { + + @Override + public void write(WorkflowOutputBuffer buffer, Serializable object) { + try (ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bytesOut)) { + out.writeObject(object); + buffer.writeBytes(bytesOut.toByteArray()); + } catch (IOException io) { + throw new UncheckedIOException(io); + } + } + + @Override + public Serializable read(WorkflowInputBuffer buffer, Class objectClass) { + try (ByteArrayInputStream bytesIn = new ByteArrayInputStream(buffer.readBytes()); + ObjectInputStream in = new ObjectInputStream(bytesIn)) { + return objectClass.cast(in.readObject()); + } catch (IOException io) { + throw new UncheckedIOException(io); + } catch (ClassNotFoundException ex) { + throw new IllegalStateException(ex); + } + } + + @Override + public Class getObjectClass() { + return Serializable.class; + } + + @Override + public int priority() { + return Integer.MAX_VALUE; + } +} diff --git a/experimental/model/src/main/resources/META-INF/services/io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller b/experimental/model/src/main/resources/META-INF/services/io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller new file mode 100644 index 000000000..a3fee7dc1 --- /dev/null +++ b/experimental/model/src/main/resources/META-INF/services/io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller @@ -0,0 +1,2 @@ +io.serverlessworkflow.impl.model.func.JavaModelMarshaller +io.serverlessworkflow.impl.model.func.SerializableObjectMarshaller \ No newline at end of file diff --git a/experimental/model/src/test/java/io/serverlessworkflow/impl/model/func/Address.java b/experimental/model/src/test/java/io/serverlessworkflow/impl/model/func/Address.java new file mode 100644 index 000000000..37a141ff8 --- /dev/null +++ b/experimental/model/src/test/java/io/serverlessworkflow/impl/model/func/Address.java @@ -0,0 +1,20 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.model.func; + +import java.io.Serializable; + +record Address(String street, int number) implements Serializable {} diff --git a/experimental/model/src/test/java/io/serverlessworkflow/impl/model/func/JavaModelSerializationTest.java b/experimental/model/src/test/java/io/serverlessworkflow/impl/model/func/JavaModelSerializationTest.java new file mode 100644 index 000000000..a42e0dab8 --- /dev/null +++ b/experimental/model/src/test/java/io/serverlessworkflow/impl/model/func/JavaModelSerializationTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.model.func; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.serverlessworkflow.impl.marshaller.DefaultBufferFactory; +import io.serverlessworkflow.impl.marshaller.WorkflowBufferFactory; +import io.serverlessworkflow.impl.marshaller.WorkflowInputBuffer; +import io.serverlessworkflow.impl.marshaller.WorkflowOutputBuffer; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class JavaModelSerializationTest { + + @Test + void testSerializableJavaModel() throws IOException { + testMarshallUnMarshall( + new JavaModel(new Person("Pepe Gotera", 32, new Address("Rue del Percebe", 13)))); + } + + private void testMarshallUnMarshall(Object object) { + WorkflowBufferFactory factory = DefaultBufferFactory.factory(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try (WorkflowOutputBuffer writer = factory.output(output)) { + writer.writeObject(object); + } + ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); + try (WorkflowInputBuffer reader = factory.input(input)) { + assertThat(reader.readObject()).isEqualTo(object); + } + } +} diff --git a/experimental/model/src/test/java/io/serverlessworkflow/impl/model/func/Person.java b/experimental/model/src/test/java/io/serverlessworkflow/impl/model/func/Person.java new file mode 100644 index 000000000..de7dba780 --- /dev/null +++ b/experimental/model/src/test/java/io/serverlessworkflow/impl/model/func/Person.java @@ -0,0 +1,20 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.model.func; + +import java.io.Serializable; + +record Person(String name, int age, Address address) implements Serializable {} diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractInputBuffer.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractInputBuffer.java similarity index 92% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractInputBuffer.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractInputBuffer.java index b79717177..5b3d66276 100644 --- a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractInputBuffer.java +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractInputBuffer.java @@ -131,10 +131,7 @@ protected Class loadClass(String className) throws ClassNotFoundException { protected Object readCustomObject() { Class objectClass = readClass(); - return customMarshallers.stream() - .filter(m -> m.getObjectClass().isAssignableFrom(objectClass)) - .findFirst() - .map(m -> m.read(this)) - .orElseThrow(() -> new IllegalArgumentException("Unsupported type " + objectClass)); + return MarshallingUtils.getCustomMarshaller(customMarshallers, objectClass) + .read(this, objectClass); } } diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractOutputBuffer.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractOutputBuffer.java similarity index 91% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractOutputBuffer.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractOutputBuffer.java index fb002800a..17612b5a1 100644 --- a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractOutputBuffer.java +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/AbstractOutputBuffer.java @@ -73,7 +73,7 @@ public WorkflowOutputBuffer writeObject(Object object) { writeLong(number); } else if (object instanceof Byte number) { writeType(Type.BYTE); - writeLong(number); + writeByte(number); } else if (object instanceof Float number) { writeType(Type.FLOAT); writeFloat(number); @@ -109,14 +109,11 @@ protected void writeClass(Class objectClass) { writeString(objectClass.getCanonicalName()); } + @SuppressWarnings({"rawtypes", "unchecked"}) protected void writeCustomObject(Object object) { CustomObjectMarshaller marshaller = - customMarshallers.stream() - .filter(m -> m.getObjectClass().isAssignableFrom(object.getClass())) - .findFirst() - .orElseThrow( - () -> new IllegalArgumentException("Unsupported type " + object.getClass())); - writeClass(marshaller.getObjectClass()); + MarshallingUtils.getCustomMarshaller(customMarshallers, object.getClass()); + writeClass(object.getClass()); marshaller.write(this, marshaller.getObjectClass().cast(object)); } diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java similarity index 93% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java index 23fbe1bb1..23e10287b 100644 --- a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java @@ -20,7 +20,7 @@ public interface CustomObjectMarshaller extends ServicePriority { void write(WorkflowOutputBuffer buffer, T object); - T read(WorkflowInputBuffer buffer); + T read(WorkflowInputBuffer buffer, Class clazz); Class getObjectClass(); } diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultBufferFactory.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultBufferFactory.java similarity index 98% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultBufferFactory.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultBufferFactory.java index ba3d2cc86..5fbc7efa3 100644 --- a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultBufferFactory.java +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultBufferFactory.java @@ -29,6 +29,7 @@ private static class DefaultBufferFactoryHolder { new DefaultBufferFactory( ServiceLoader.load(CustomObjectMarshaller.class).stream() .map(ServiceLoader.Provider::get) + .sorted() .toList()); } diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultInputBuffer.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultInputBuffer.java similarity index 100% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultInputBuffer.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultInputBuffer.java diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultOutputBuffer.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultOutputBuffer.java similarity index 100% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultOutputBuffer.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/DefaultOutputBuffer.java diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/MarshallingUtils.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/MarshallingUtils.java similarity index 73% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/MarshallingUtils.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/MarshallingUtils.java index e82333951..d71deb5ab 100644 --- a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/MarshallingUtils.java +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/MarshallingUtils.java @@ -19,6 +19,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.time.Instant; +import java.util.Collection; import java.util.function.BiConsumer; import java.util.function.Function; @@ -95,4 +96,32 @@ private static T readValue( return valueConsumer.apply(buffer); } } + + /** + * Retrieve more proper marshaler for the given class. Collection is assumed to be already sorted + * by priority. No matter which priority is given, if the object class is equal to the marshaler + * class, it should have precedence over an object class which is assignable to the marshaler + * class. + * + * @param marshallers Priority Sorted collection of marshalers available on classpath + * @param clazz The class of the object being marshaled + * @return The most suitable marshaler for that object class + * @throws IllegalArgumentException if no marshaler is found for that object class + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static CustomObjectMarshaller getCustomMarshaller( + Collection marshallers, Class clazz) { + CustomObjectMarshaller assignable = null; + for (CustomObjectMarshaller marshaller : marshallers) { + if (marshaller.getObjectClass().equals(clazz)) { + return marshaller; + } else if (marshaller.getObjectClass().isAssignableFrom(clazz) && assignable == null) { + assignable = marshaller; + } + } + if (assignable == null) { + throw new IllegalArgumentException("Cannot find proper marshaler for class " + clazz); + } + return assignable; + } } diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/TaskStatus.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/TaskStatus.java similarity index 100% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/TaskStatus.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/TaskStatus.java diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/Type.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/Type.java similarity index 100% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/Type.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/Type.java diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowBufferFactory.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowBufferFactory.java similarity index 100% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowBufferFactory.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowBufferFactory.java diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowInputBuffer.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowInputBuffer.java similarity index 100% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowInputBuffer.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowInputBuffer.java diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowOutputBuffer.java b/impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowOutputBuffer.java similarity index 100% rename from impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowOutputBuffer.java rename to impl/core/src/main/java/io/serverlessworkflow/impl/marshaller/WorkflowOutputBuffer.java diff --git a/impl/core/src/test/java/io/serverlessworkflow/impl/marshaller/Employee.java b/impl/core/src/test/java/io/serverlessworkflow/impl/marshaller/Employee.java new file mode 100644 index 000000000..1a8d7455b --- /dev/null +++ b/impl/core/src/test/java/io/serverlessworkflow/impl/marshaller/Employee.java @@ -0,0 +1,18 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.marshaller; + +class Employee extends Person {} diff --git a/impl/core/src/test/java/io/serverlessworkflow/impl/marshaller/MarshallingUtilsTest.java b/impl/core/src/test/java/io/serverlessworkflow/impl/marshaller/MarshallingUtilsTest.java new file mode 100644 index 000000000..51ade121f --- /dev/null +++ b/impl/core/src/test/java/io/serverlessworkflow/impl/marshaller/MarshallingUtilsTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.marshaller; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class MarshallingUtilsTest { + + @Test + void testCustomMarshallers() { + CustomObjectMarshaller personMarshaller = Mockito.spy(CustomObjectMarshaller.class); + Mockito.when(personMarshaller.priority()).thenReturn(1); + Mockito.when(personMarshaller.getObjectClass()).thenReturn(Person.class); + CustomObjectMarshaller employeeMarshaller = Mockito.spy(CustomObjectMarshaller.class); + Mockito.when(employeeMarshaller.priority()).thenReturn(2); + Mockito.when(employeeMarshaller.getObjectClass()).thenReturn(Employee.class); + CustomObjectMarshaller objectMarshaller = Mockito.spy(CustomObjectMarshaller.class); + Mockito.when(objectMarshaller.priority()).thenReturn(3); + Mockito.when(objectMarshaller.getObjectClass()).thenReturn(Object.class); + Object employee = new Employee(); + Object person = new Person(); + Object other = new byte[2]; + + List marshallers = + Stream.of(objectMarshaller, employeeMarshaller, personMarshaller) + .sorted() + .collect(Collectors.toList()); + assertThat(marshallers).containsExactly(personMarshaller, employeeMarshaller, objectMarshaller); + assertThat(MarshallingUtils.getCustomMarshaller(marshallers, employee.getClass())) + .isEqualTo(employeeMarshaller); + assertThat(MarshallingUtils.getCustomMarshaller(marshallers, person.getClass())) + .isEqualTo(personMarshaller); + assertThat(MarshallingUtils.getCustomMarshaller(marshallers, other.getClass())) + .isEqualTo(objectMarshaller); + } +} diff --git a/impl/core/src/test/java/io/serverlessworkflow/impl/marshaller/Person.java b/impl/core/src/test/java/io/serverlessworkflow/impl/marshaller/Person.java new file mode 100644 index 000000000..a618f9e26 --- /dev/null +++ b/impl/core/src/test/java/io/serverlessworkflow/impl/marshaller/Person.java @@ -0,0 +1,18 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.marshaller; + +class Person {} diff --git a/impl/persistence/jackson-marshaller/src/main/java/io/serverlessworkflow/impl/marshaller/jackson/JacksonModelMarshaller.java b/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/AbstractJacksonMarshaller.java similarity index 69% rename from impl/persistence/jackson-marshaller/src/main/java/io/serverlessworkflow/impl/marshaller/jackson/JacksonModelMarshaller.java rename to impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/AbstractJacksonMarshaller.java index ba467b766..47f73d25d 100644 --- a/impl/persistence/jackson-marshaller/src/main/java/io/serverlessworkflow/impl/marshaller/jackson/JacksonModelMarshaller.java +++ b/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/AbstractJacksonMarshaller.java @@ -13,21 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.serverlessworkflow.impl.marshaller.jackson; +package io.serverlessworkflow.impl.model.jackson; import com.fasterxml.jackson.core.JsonProcessingException; import io.serverlessworkflow.impl.jackson.JsonUtils; import io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller; import io.serverlessworkflow.impl.marshaller.WorkflowInputBuffer; import io.serverlessworkflow.impl.marshaller.WorkflowOutputBuffer; -import io.serverlessworkflow.impl.model.jackson.JacksonModel; import java.io.IOException; import java.io.UncheckedIOException; -public class JacksonModelMarshaller implements CustomObjectMarshaller { +abstract class AbstractJacksonMarshaller implements CustomObjectMarshaller { @Override - public void write(WorkflowOutputBuffer buffer, JacksonModel object) { + public void write(WorkflowOutputBuffer buffer, T object) { try { buffer.writeBytes(JsonUtils.mapper().writeValueAsBytes(object)); } catch (JsonProcessingException e) { @@ -36,17 +35,11 @@ public void write(WorkflowOutputBuffer buffer, JacksonModel object) { } @Override - public JacksonModel read(WorkflowInputBuffer buffer) { + public T read(WorkflowInputBuffer buffer, Class clazz) { try { - JacksonModel model = JsonUtils.mapper().readValue(buffer.readBytes(), JacksonModel.class); - return model == null ? JacksonModel.NULL : model; + return JsonUtils.mapper().readValue(buffer.readBytes(), clazz); } catch (IOException e) { throw new UncheckedIOException(e); } } - - @Override - public Class getObjectClass() { - return JacksonModel.class; - } } diff --git a/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonModel.java b/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonModel.java index e30581711..aae12ba9b 100644 --- a/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonModel.java +++ b/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonModel.java @@ -30,6 +30,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.Objects; import java.util.Optional; @JsonSerialize(using = JacksonModelSerializer.class) @@ -131,4 +132,18 @@ protected Optional convert(Class clazz) { ? Optional.of(clazz.cast(node)) : Optional.of(JsonUtils.mapper().convertValue(node, clazz)); } + + @Override + public int hashCode() { + return Objects.hash(node); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + JacksonModel other = (JacksonModel) obj; + return Objects.equals(node, other.node); + } } diff --git a/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonModelMarshaller.java b/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonModelMarshaller.java new file mode 100644 index 000000000..ca95e82fb --- /dev/null +++ b/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonModelMarshaller.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.model.jackson; + +import io.serverlessworkflow.impl.marshaller.WorkflowInputBuffer; + +public class JacksonModelMarshaller extends AbstractJacksonMarshaller { + + @Override + public JacksonModel read(WorkflowInputBuffer buffer, Class clazz) { + JacksonModel model = super.read(buffer, clazz); + return model == null ? JacksonModel.NULL : model; + } + + @Override + public Class getObjectClass() { + return JacksonModel.class; + } +} diff --git a/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonObjectMarshaller.java b/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonObjectMarshaller.java new file mode 100644 index 000000000..1f406f804 --- /dev/null +++ b/impl/model/src/main/java/io/serverlessworkflow/impl/model/jackson/JacksonObjectMarshaller.java @@ -0,0 +1,29 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.model.jackson; + +public class JacksonObjectMarshaller extends AbstractJacksonMarshaller { + + @Override + public Class getObjectClass() { + return Object.class; + } + + @Override + public int priority() { + return Integer.MAX_VALUE; + } +} diff --git a/impl/model/src/main/resources/META-INF/services/io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller b/impl/model/src/main/resources/META-INF/services/io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller new file mode 100644 index 000000000..ea94d9455 --- /dev/null +++ b/impl/model/src/main/resources/META-INF/services/io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller @@ -0,0 +1,2 @@ +io.serverlessworkflow.impl.model.jackson.JacksonModelMarshaller +io.serverlessworkflow.impl.model.jackson.JacksonObjectMarshaller \ No newline at end of file diff --git a/impl/model/src/test/java/io/serverlessworkflow/impl/model/jackson/Employee.java b/impl/model/src/test/java/io/serverlessworkflow/impl/model/jackson/Employee.java new file mode 100644 index 000000000..6d6d2e02e --- /dev/null +++ b/impl/model/src/test/java/io/serverlessworkflow/impl/model/jackson/Employee.java @@ -0,0 +1,18 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.model.jackson; + +record Employee(String name, String company) {} diff --git a/impl/model/src/test/java/io/serverlessworkflow/impl/model/jackson/JacksonModelSerializationTest.java b/impl/model/src/test/java/io/serverlessworkflow/impl/model/jackson/JacksonModelSerializationTest.java new file mode 100644 index 000000000..85e5bacdf --- /dev/null +++ b/impl/model/src/test/java/io/serverlessworkflow/impl/model/jackson/JacksonModelSerializationTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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.serverlessworkflow.impl.model.jackson; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.serverlessworkflow.impl.jackson.JsonUtils; +import io.serverlessworkflow.impl.marshaller.DefaultBufferFactory; +import io.serverlessworkflow.impl.marshaller.WorkflowBufferFactory; +import io.serverlessworkflow.impl.marshaller.WorkflowInputBuffer; +import io.serverlessworkflow.impl.marshaller.WorkflowOutputBuffer; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class JacksonModelSerializationTest { + + @Test + void testObject() throws IOException { + testMarshallUnMarshall(new Employee("Mortadelo", "TIA")); + } + + @Test + void testModel() throws IOException { + testMarshallUnMarshall( + new JacksonModel(JsonUtils.mapper().createObjectNode().put("Mortadelo", "TIA"))); + } + + private void testMarshallUnMarshall(Object object) { + WorkflowBufferFactory factory = DefaultBufferFactory.factory(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try (WorkflowOutputBuffer writer = factory.output(output)) { + writer.writeObject(object); + } + ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); + try (WorkflowInputBuffer reader = factory.input(input)) { + assertThat(reader.readObject()).isEqualTo(object); + } + } +} diff --git a/impl/persistence/jackson-marshaller/pom.xml b/impl/persistence/jackson-marshaller/pom.xml deleted file mode 100644 index 7cd1447b8..000000000 --- a/impl/persistence/jackson-marshaller/pom.xml +++ /dev/null @@ -1,20 +0,0 @@ - - 4.0.0 - - io.serverlessworkflow - serverlessworkflow-persistence - 8.0.0-SNAPSHOT - - serverlessworkflow-persistence-jackson-marshaller - Serverless Workflow :: Impl :: Persistence:: Marshaller:: Jackson - - - io.serverlessworkflow - serverlessworkflow-persistence-api - - - io.serverlessworkflow - serverlessworkflow-impl-model - - - \ No newline at end of file diff --git a/impl/persistence/jackson-marshaller/src/main/resources/META-INF/services/io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller b/impl/persistence/jackson-marshaller/src/main/resources/META-INF/services/io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller deleted file mode 100644 index 81b326366..000000000 --- a/impl/persistence/jackson-marshaller/src/main/resources/META-INF/services/io.serverlessworkflow.impl.marshaller.CustomObjectMarshaller +++ /dev/null @@ -1 +0,0 @@ -io.serverlessworkflow.impl.marshaller.jackson.JacksonModelMarshaller \ No newline at end of file diff --git a/impl/persistence/pom.xml b/impl/persistence/pom.xml index e705fab75..85cdea06b 100644 --- a/impl/persistence/pom.xml +++ b/impl/persistence/pom.xml @@ -9,7 +9,6 @@ Serverless Workflow :: Implementation:: Persistence pom - jackson-marshaller mvstore bigmap api diff --git a/impl/persistence/tests/pom.xml b/impl/persistence/tests/pom.xml index dfe8d28fb..5f9141f15 100644 --- a/impl/persistence/tests/pom.xml +++ b/impl/persistence/tests/pom.xml @@ -45,9 +45,5 @@ io.serverlessworkflow serverlessworkflow-api - - io.serverlessworkflow - serverlessworkflow-persistence-jackson-marshaller - \ No newline at end of file diff --git a/impl/pom.xml b/impl/pom.xml index bec75155f..ee68617dc 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -82,11 +82,6 @@ ${project.version} test - - io.serverlessworkflow - serverlessworkflow-persistence-jackson-marshaller - ${project.version} - io.serverlessworkflow serverlessworkflow-persistence-mvstore diff --git a/impl/test/pom.xml b/impl/test/pom.xml index f040989bf..94e8d77bc 100644 --- a/impl/test/pom.xml +++ b/impl/test/pom.xml @@ -20,11 +20,6 @@ io.serverlessworkflow serverlessworkflow-persistence-mvstore - - io.serverlessworkflow - serverlessworkflow-persistence-jackson-marshaller - test - io.serverlessworkflow serverlessworkflow-impl-http