mirror of https://github.com/dapr/java-sdk.git
Faster JSON building + separate auto-gen jar + tests. (#55)
This commit is contained in:
parent
14f2304c8c
commit
9a10a960e8
|
@ -7,12 +7,12 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>io.dapr</groupId>
|
<groupId>io.dapr</groupId>
|
||||||
<artifactId>dapr-sdk-parent</artifactId>
|
<artifactId>dapr-sdk-parent</artifactId>
|
||||||
<version>0.3.0-preview01</version>
|
<version>0.2.0-preview01</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dapr-sdk-examples</artifactId>
|
<artifactId>dapr-sdk-examples</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<version>0.3.0-preview01</version>
|
<version>0.2.0-preview01</version>
|
||||||
<name>dapr-sdk-examples</name>
|
<name>dapr-sdk-examples</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.dapr</groupId>
|
<groupId>io.dapr</groupId>
|
||||||
<artifactId>dapr-sdk</artifactId>
|
<artifactId>dapr-sdk</artifactId>
|
||||||
<version>0.3.0-preview01</version>
|
<version>0.2.0-preview01</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
3
pom.xml
3
pom.xml
|
@ -7,7 +7,7 @@
|
||||||
<groupId>io.dapr</groupId>
|
<groupId>io.dapr</groupId>
|
||||||
<artifactId>dapr-sdk-parent</artifactId>
|
<artifactId>dapr-sdk-parent</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>0.3.0-preview01</version>
|
<version>0.2.0-preview01</version>
|
||||||
<name>dapr-sdk-parent</name>
|
<name>dapr-sdk-parent</name>
|
||||||
<description>SDK for Dapr.</description>
|
<description>SDK for Dapr.</description>
|
||||||
<url>https://dapr.io</url>
|
<url>https://dapr.io</url>
|
||||||
|
@ -77,6 +77,7 @@
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
|
<module>sdk-autogen</module>
|
||||||
<module>sdk</module>
|
<module>sdk</module>
|
||||||
<module>examples</module>
|
<module>examples</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
<project
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>io.dapr</groupId>
|
||||||
|
<artifactId>dapr-sdk-parent</artifactId>
|
||||||
|
<version>0.2.0-preview01</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>dapr-sdk-autogen</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>0.2.0-preview01</version>
|
||||||
|
<name>dapr-sdk-autogen</name>
|
||||||
|
<description>Auto-generated SDK for Dapr</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<protobuf.output.directory>${project.build.directory}/generated-sources</protobuf.output.directory>
|
||||||
|
<protobuf.input.directory>${project.parent.basedir}/proto</protobuf.input.directory>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.annotation</groupId>
|
||||||
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-netty-shaded</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-protobuf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-stub</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-testing</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.protobuf</groupId>
|
||||||
|
<artifactId>protobuf-java-util</artifactId>
|
||||||
|
<version>${protobuf.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.os72</groupId>
|
||||||
|
<artifactId>protoc-jar-maven-plugin</artifactId>
|
||||||
|
<version>3.10.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.os72</groupId>
|
||||||
|
<artifactId>protoc-jar-maven-plugin</artifactId>
|
||||||
|
<version>3.10.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>generate-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>run</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<protocVersion>${protobuf.version}</protocVersion>
|
||||||
|
<addProtoSources>inputs</addProtoSources>
|
||||||
|
<includeMavenTypes>direct</includeMavenTypes>
|
||||||
|
<includeStdTypes>true</includeStdTypes>
|
||||||
|
<inputDirectories>
|
||||||
|
<include>${protobuf.input.directory}/dapr</include>
|
||||||
|
<include>${protobuf.input.directory}/daprclient</include>
|
||||||
|
</inputDirectories>
|
||||||
|
<outputTargets>
|
||||||
|
<outputTarget>
|
||||||
|
<type>java</type>
|
||||||
|
<outputDirectory>${protobuf.output.directory}</outputDirectory>
|
||||||
|
</outputTarget>
|
||||||
|
<outputTarget>
|
||||||
|
<type>grpc-java</type>
|
||||||
|
<outputDirectory>${protobuf.output.directory}</outputDirectory>
|
||||||
|
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}</pluginArtifact>
|
||||||
|
</outputTarget>
|
||||||
|
</outputTargets>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>attach-sources</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jar-no-fork</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
77
sdk/pom.xml
77
sdk/pom.xml
|
@ -7,21 +7,21 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>io.dapr</groupId>
|
<groupId>io.dapr</groupId>
|
||||||
<artifactId>dapr-sdk-parent</artifactId>
|
<artifactId>dapr-sdk-parent</artifactId>
|
||||||
<version>0.3.0-preview01</version>
|
<version>0.2.0-preview01</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dapr-sdk</artifactId>
|
<artifactId>dapr-sdk</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<version>0.3.0-preview01</version>
|
<version>0.2.0-preview01</version>
|
||||||
<name>dapr-sdk</name>
|
<name>dapr-sdk</name>
|
||||||
<description>SDK for Dapr</description>
|
<description>SDK for Dapr</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<protobuf.output.directory>${project.build.directory}/generated-sources</protobuf.output.directory>
|
|
||||||
<protobuf.input.directory>${project.parent.basedir}/proto</protobuf.input.directory>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.dapr</groupId>
|
||||||
|
<artifactId>dapr-sdk-autogen</artifactId>
|
||||||
|
<version>0.2.0-preview01</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
@ -37,34 +37,11 @@
|
||||||
<artifactId>okhttp</artifactId>
|
<artifactId>okhttp</artifactId>
|
||||||
<version>4.2.1</version>
|
<version>4.2.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>io.grpc</groupId>
|
|
||||||
<artifactId>grpc-netty-shaded</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.grpc</groupId>
|
|
||||||
<artifactId>grpc-protobuf</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.grpc</groupId>
|
|
||||||
<artifactId>grpc-stub</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.annotation</groupId>
|
<groupId>javax.annotation</groupId>
|
||||||
<artifactId>javax.annotation-api</artifactId>
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>io.grpc</groupId>
|
|
||||||
<artifactId>grpc-testing</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.protobuf</groupId>
|
|
||||||
<artifactId>protobuf-java-util</artifactId>
|
|
||||||
<version>${protobuf.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
@ -75,50 +52,10 @@
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.os72</groupId>
|
|
||||||
<artifactId>protoc-jar-maven-plugin</artifactId>
|
|
||||||
<version>3.10.1</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<groupId>com.github.os72</groupId>
|
|
||||||
<artifactId>protoc-jar-maven-plugin</artifactId>
|
|
||||||
<version>3.10.1</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>generate-sources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>run</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<protocVersion>${protobuf.version}</protocVersion>
|
|
||||||
<addProtoSources>inputs</addProtoSources>
|
|
||||||
<includeMavenTypes>direct</includeMavenTypes>
|
|
||||||
<includeStdTypes>true</includeStdTypes>
|
|
||||||
<inputDirectories>
|
|
||||||
<include>${protobuf.input.directory}/dapr</include>
|
|
||||||
<include>${protobuf.input.directory}/daprclient</include>
|
|
||||||
</inputDirectories>
|
|
||||||
<outputTargets>
|
|
||||||
<outputTarget>
|
|
||||||
<type>java</type>
|
|
||||||
<outputDirectory>${protobuf.output.directory}</outputDirectory>
|
|
||||||
</outputTarget>
|
|
||||||
<outputTarget>
|
|
||||||
<type>grpc-java</type>
|
|
||||||
<outputDirectory>${protobuf.output.directory}</outputDirectory>
|
|
||||||
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}</pluginArtifact>
|
|
||||||
</outputTarget>
|
|
||||||
</outputTargets>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
|
|
@ -152,20 +152,20 @@ public abstract class AbstractDaprClient {
|
||||||
public interface DaprHttpCallback {
|
public interface DaprHttpCallback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called when the server response was not 2xx or when an exception was
|
* Called when the server response was not 2xx or when an exception was
|
||||||
* thrown in the process
|
* thrown in the process
|
||||||
*
|
*
|
||||||
* @param response - in case of server error (4xx, 5xx) this contains the
|
* @param call - in case of server error (4xx, 5xx) this contains the
|
||||||
* server response in case of IO exception this is null
|
* server response in case of IO exception this is null
|
||||||
* @param throwable - contains the exception. in case of server error (4xx,
|
* @param e - contains the exception. in case of server error (4xx,
|
||||||
* 5xx) this is null
|
* 5xx) this is null
|
||||||
*/
|
*/
|
||||||
public void onFailure(Call call, Exception e);
|
public void onFailure(Call call, Exception e);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* contains the server response
|
* Contains the server response
|
||||||
*
|
*
|
||||||
* @param response
|
* @param response Success response.
|
||||||
*/
|
*/
|
||||||
public void onSuccess(String response);
|
public void onSuccess(String response);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ public class ActorRuntime {
|
||||||
* Registers an actor with the runtime.
|
* Registers an actor with the runtime.
|
||||||
*
|
*
|
||||||
* @param clazz The type of actor.
|
* @param clazz The type of actor.
|
||||||
|
* @param <T> Actor class type.
|
||||||
*/
|
*/
|
||||||
public <T extends AbstractActor> void RegisterActor(Class<T> clazz) {
|
public <T extends AbstractActor> void RegisterActor(Class<T> clazz) {
|
||||||
RegisterActor(clazz, null);
|
RegisterActor(clazz, null);
|
||||||
|
@ -88,6 +89,7 @@ public class ActorRuntime {
|
||||||
*
|
*
|
||||||
* @param clazz The type of actor.
|
* @param clazz The type of actor.
|
||||||
* @param actorFactory An optional factory to create actors.
|
* @param actorFactory An optional factory to create actors.
|
||||||
|
* @param <T> Actor class type.
|
||||||
* This can be used for dependency injection into actors.
|
* This can be used for dependency injection into actors.
|
||||||
*/
|
*/
|
||||||
public <T extends AbstractActor> void RegisterActor(Class<T> clazz, ActorFactory actorFactory) {
|
public <T extends AbstractActor> void RegisterActor(Class<T> clazz, ActorFactory actorFactory) {
|
||||||
|
@ -95,7 +97,7 @@ public class ActorRuntime {
|
||||||
|
|
||||||
ActorFactory actualActorFactory = actorFactory != null ? actorFactory : new DefaultActorFactory<T>(actorTypeInfo);
|
ActorFactory actualActorFactory = actorFactory != null ? actorFactory : new DefaultActorFactory<T>(actorTypeInfo);
|
||||||
// TODO: Refactor into a Builder class.
|
// TODO: Refactor into a Builder class.
|
||||||
DaprStateAsyncProvider stateProvider = new DaprStateAsyncProvider(this.appToDaprAsyncClient, new ActorStateProviderSerializer());
|
DaprStateAsyncProvider stateProvider = new DaprStateAsyncProvider(this.appToDaprAsyncClient, new ActorStateSerializer());
|
||||||
ActorService actorService = new ActorServiceImpl(actorTypeInfo, stateProvider, actualActorFactory);
|
ActorService actorService = new ActorServiceImpl(actorTypeInfo, stateProvider, actualActorFactory);
|
||||||
|
|
||||||
// Create ActorManagers, override existing entry if registered again.
|
// Create ActorManagers, override existing entry if registered again.
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
|
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a state change for an actor.
|
* Represents a state change for an actor.
|
||||||
* @param <T> Type of the value being changed.
|
* @param <T> Type of the value being changed.
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Microsoft Corporation.
|
|
||||||
* Licensed under the MIT License.
|
|
||||||
*/
|
|
||||||
package io.dapr.actors.runtime;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes and deserializes an object.
|
|
||||||
*/
|
|
||||||
class ActorStateProviderSerializer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shared Json serializer/deserializer as per Jackson's documentation.
|
|
||||||
*/
|
|
||||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes a given state object into byte array.
|
|
||||||
*
|
|
||||||
* @param state State object to be serialized.
|
|
||||||
* @return Array of bytes[] with the serialized content.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
String serialize(Object state) throws IOException {
|
|
||||||
return OBJECT_MAPPER.writeValueAsString(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserializes the byte array into the original object.
|
|
||||||
*
|
|
||||||
* @param json String to be parsed.
|
|
||||||
* @param clazz Type of the object being deserialized.
|
|
||||||
* @param <T> Generic type of the object being deserialized.
|
|
||||||
* @return Object of type T.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
<T> T deserialize(String json, Class<T> clazz) throws IOException {
|
|
||||||
return OBJECT_MAPPER.readValue(json, clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
* Licensed under the MIT License.
|
||||||
|
*/
|
||||||
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes and deserializes an object.
|
||||||
|
*/
|
||||||
|
class ActorStateSerializer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared Json serializer/deserializer as per Jackson's documentation.
|
||||||
|
*/
|
||||||
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes a given state object into byte array.
|
||||||
|
*
|
||||||
|
* @param state State object to be serialized.
|
||||||
|
* @return Array of bytes[] with the serialized content.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
<T> String serialize(T state) throws IOException {
|
||||||
|
if (state == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.getClass() == String.class) {
|
||||||
|
return state.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPrimitive(state.getClass())) {
|
||||||
|
return state.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not string, not primitive, so it is a complex type: we use JSON for that.
|
||||||
|
return OBJECT_MAPPER.writeValueAsString(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes the byte array into the original object.
|
||||||
|
*
|
||||||
|
* @param value String to be parsed.
|
||||||
|
* @param clazz Type of the object being deserialized.
|
||||||
|
* @param <T> Generic type of the object being deserialized.
|
||||||
|
* @return Object of type T.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
<T> T deserialize(String value, Class<T> clazz) throws IOException {
|
||||||
|
if (clazz == String.class) {
|
||||||
|
return (T) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPrimitive(clazz)) {
|
||||||
|
return parse(value, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not string, not primitive, so it is a complex type: we use JSON for that.
|
||||||
|
return OBJECT_MAPPER.readValue(value, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPrimitive(Class<?> clazz) {
|
||||||
|
if (clazz == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (clazz.isPrimitive() ||
|
||||||
|
(clazz == Boolean.class) ||
|
||||||
|
(clazz == Character.class) ||
|
||||||
|
(clazz == Byte.class) ||
|
||||||
|
(clazz == Short.class) ||
|
||||||
|
(clazz == Integer.class) ||
|
||||||
|
(clazz == Long.class) ||
|
||||||
|
(clazz == Float.class) ||
|
||||||
|
(clazz == Double.class) ||
|
||||||
|
(clazz == Void.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T parse(String value, Class<T> clazz) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Boolean.class == clazz) || (boolean.class == clazz)) return (T) Boolean.valueOf(value);
|
||||||
|
if ((Byte.class == clazz) || (byte.class == clazz)) return (T) Byte.valueOf(value);
|
||||||
|
if ((Short.class == clazz) || (short.class == clazz)) return (T) Short.valueOf(value);
|
||||||
|
if ((Integer.class == clazz) || (int.class == clazz)) return (T) Integer.valueOf(value);
|
||||||
|
if ((Long.class == clazz) || (long.class == clazz)) return (T) Long.valueOf(value);
|
||||||
|
if ((Float.class == clazz) || (float.class == clazz)) return (T) Float.valueOf(value);
|
||||||
|
if ((Double.class == clazz) || (double.class == clazz)) return (T) Double.valueOf(value);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,14 @@
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@ -14,9 +18,9 @@ import java.util.function.Function;
|
||||||
class ActorTimerImpl implements ActorTimer {
|
class ActorTimerImpl implements ActorTimer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared Json serializer/deserializer as per Jackson's documentation, used only for this class.
|
* Shared Json Factory as per Jackson's documentation, used only for this class.
|
||||||
*/
|
*/
|
||||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
private static final JsonFactory JSON_FACTORY = new JsonFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actor that owns this timer.
|
* Actor that owns this timer.
|
||||||
|
@ -118,9 +122,15 @@ class ActorTimerImpl implements ActorTimer {
|
||||||
* @return JSON.
|
* @return JSON.
|
||||||
*/
|
*/
|
||||||
String serialize() throws IOException {
|
String serialize() throws IOException {
|
||||||
ObjectNode objectNode = OBJECT_MAPPER.createObjectNode();
|
try (Writer writer = new StringWriter()) {
|
||||||
objectNode.put("dueTime", ConverterUtils.ConvertDurationToDaprFormat(this.dueTime));
|
JsonGenerator generator = JSON_FACTORY.createGenerator(writer);
|
||||||
objectNode.put("period", ConverterUtils.ConvertDurationToDaprFormat(this.period));
|
generator.writeStartObject();
|
||||||
return OBJECT_MAPPER.writeValueAsString(objectNode);
|
generator.writeStringField("dueTime", ConverterUtils.ConvertDurationToDaprFormat(this.dueTime));
|
||||||
|
generator.writeStringField("period", ConverterUtils.ConvertDurationToDaprFormat(this.period));
|
||||||
|
generator.writeEndObject();
|
||||||
|
generator.close();
|
||||||
|
writer.flush();
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,14 +5,13 @@
|
||||||
|
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State Provider to interact with Dapr runtime to handle state.
|
* State Provider to interact with Dapr runtime to handle state.
|
||||||
|
@ -20,15 +19,15 @@ import java.util.Collection;
|
||||||
class DaprStateAsyncProvider {
|
class DaprStateAsyncProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared Json serializer/deserializer as per Jackson's documentation, used only for this class.
|
* Shared Json Factory as per Jackson's documentation, used only for this class.
|
||||||
*/
|
*/
|
||||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
private static final JsonFactory JSON_FACTORY = new JsonFactory();
|
||||||
|
|
||||||
private final AppToDaprAsyncClient daprAsyncClient;
|
private final AppToDaprAsyncClient daprAsyncClient;
|
||||||
|
|
||||||
private final ActorStateProviderSerializer serializer;
|
private final ActorStateSerializer serializer;
|
||||||
|
|
||||||
DaprStateAsyncProvider(AppToDaprAsyncClient daprAsyncClient, ActorStateProviderSerializer serializer) {
|
DaprStateAsyncProvider(AppToDaprAsyncClient daprAsyncClient, ActorStateSerializer serializer) {
|
||||||
this.daprAsyncClient = daprAsyncClient;
|
this.daprAsyncClient = daprAsyncClient;
|
||||||
this.serializer = serializer;
|
this.serializer = serializer;
|
||||||
}
|
}
|
||||||
|
@ -36,11 +35,9 @@ class DaprStateAsyncProvider {
|
||||||
<T> Mono<T> load(String actorType, String actorId, String stateName, Class<T> clazz) {
|
<T> Mono<T> load(String actorType, String actorId, String stateName, Class<T> clazz) {
|
||||||
Mono<String> result = this.daprAsyncClient.getState(actorType, actorId, stateName);
|
Mono<String> result = this.daprAsyncClient.getState(actorType, actorId, stateName);
|
||||||
|
|
||||||
return result.map(s -> {
|
return result
|
||||||
if (s == null) {
|
.filter(s -> (s != null) && (!s.isEmpty()))
|
||||||
return (T)null;
|
.map(s -> {
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return this.serializer.deserialize(s, clazz);
|
return this.serializer.deserialize(s, clazz);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -79,14 +76,20 @@ class DaprStateAsyncProvider {
|
||||||
* @param stateChanges Collection of changes to be performed transactionally.
|
* @param stateChanges Collection of changes to be performed transactionally.
|
||||||
* @return Void.
|
* @return Void.
|
||||||
*/
|
*/
|
||||||
Mono<Void> apply(String actorType, String actorId, Collection<ActorStateChange> stateChanges)
|
Mono<Void> apply(String actorType, String actorId, ActorStateChange... stateChanges)
|
||||||
{
|
{
|
||||||
if ((stateChanges == null) || stateChanges.isEmpty()) {
|
if ((stateChanges == null) || stateChanges.length == 0) {
|
||||||
return Mono.just(null);
|
return Mono.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructing the JSON "manually" to avoid creating transient classes to be parsed.
|
int count = 0;
|
||||||
ArrayNode operations = OBJECT_MAPPER.createArrayNode();
|
// Constructing the JSON via a stream API to avoid creating transient objects to be instantiated.
|
||||||
|
String payload = null;
|
||||||
|
try (Writer writer = new StringWriter()) {
|
||||||
|
JsonGenerator generator = JSON_FACTORY.createGenerator(writer);
|
||||||
|
// Start array
|
||||||
|
generator.writeStartArray();
|
||||||
|
|
||||||
for (ActorStateChange stateChange : stateChanges) {
|
for (ActorStateChange stateChange : stateChanges) {
|
||||||
if ((stateChange == null) || (stateChange.getChangeKind() == null)) {
|
if ((stateChange == null) || (stateChange.getChangeKind() == null)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -97,32 +100,41 @@ class DaprStateAsyncProvider {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
count++;
|
||||||
ObjectNode operation = OBJECT_MAPPER.createObjectNode();
|
|
||||||
operation.set("operation", operation.textNode(operationName));
|
// Start operation object.
|
||||||
ObjectNode request = OBJECT_MAPPER.createObjectNode();
|
generator.writeStartObject();
|
||||||
request.put("key", stateChange.getStateName());
|
generator.writeStringField("operation", operationName);
|
||||||
|
|
||||||
|
// Start request object.
|
||||||
|
generator.writeObjectFieldStart("request");
|
||||||
|
generator.writeStringField("key", stateChange.getStateName());
|
||||||
if ((stateChange.getChangeKind() == ActorStateChangeKind.UPDATE) || (stateChange.getChangeKind() == ActorStateChangeKind.ADD)) {
|
if ((stateChange.getChangeKind() == ActorStateChangeKind.UPDATE) || (stateChange.getChangeKind() == ActorStateChangeKind.ADD)) {
|
||||||
request.put("value", this.serializer.serialize(stateChange.getValue()));
|
generator.writeStringField("value", this.serializer.serialize(stateChange.getValue()));
|
||||||
|
}
|
||||||
|
// End request object.
|
||||||
|
generator.writeEndObject();
|
||||||
|
|
||||||
|
// End operation object.
|
||||||
|
generator.writeEndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
operations.add(operation);
|
// End array
|
||||||
|
generator.writeEndArray();
|
||||||
|
|
||||||
|
generator.close();
|
||||||
|
writer.flush();
|
||||||
|
payload = writer.toString();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return Mono.error(e);
|
return Mono.error(e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (operations.size() == 0) {
|
if (count == 0) {
|
||||||
// No-op since there is no operation to be performed.
|
// No-op since there is no operation to be performed.
|
||||||
Mono.just(null);
|
Mono.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return this.daprAsyncClient.saveStateTransactionally(actorType, actorId, payload);
|
||||||
return this.daprAsyncClient.saveStateTransactionally(actorType, actorId, OBJECT_MAPPER.writeValueAsString(operations));
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return Mono.error(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,248 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
* Licensed under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the state store facade.
|
||||||
|
*/
|
||||||
|
public class DaprStateAsyncProviderTest {
|
||||||
|
|
||||||
|
private static final ActorStateSerializer SERIALIZER = new ActorStateSerializer();
|
||||||
|
|
||||||
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
private static final double EPSILON = 1e-10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used to test JSON serialization.
|
||||||
|
*/
|
||||||
|
public static final class Customer {
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Customer customer = (Customer) o;
|
||||||
|
return id == customer.id &&
|
||||||
|
Objects.equals(name, customer.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void happyCaseApply() {
|
||||||
|
AppToDaprAsyncClient daprAsyncClient = mock(AppToDaprAsyncClient.class);
|
||||||
|
when(daprAsyncClient
|
||||||
|
.saveStateTransactionally(
|
||||||
|
eq("MyActor"),
|
||||||
|
eq("123"),
|
||||||
|
argThat(s -> {
|
||||||
|
try {
|
||||||
|
JsonNode node = OBJECT_MAPPER.readTree(s);
|
||||||
|
if (node == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.size() != 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean foundInsertName = false;
|
||||||
|
boolean foundUpdateZipcode = false;
|
||||||
|
boolean foundDeleteFlag = false;
|
||||||
|
for (JsonNode operation : node) {
|
||||||
|
if (operation.get("operation") == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (operation.get("request") == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String opName = operation.get("operation").asText();
|
||||||
|
String key = operation.get("request").get("key").asText();
|
||||||
|
JsonNode valueNode = operation.get("request").get("value");
|
||||||
|
|
||||||
|
foundInsertName |= "upsert".equals(opName) &&
|
||||||
|
"name".equals(key) &&
|
||||||
|
"Jon Doe".equals(valueNode.asText());
|
||||||
|
foundUpdateZipcode |= "upsert".equals(opName) &&
|
||||||
|
"zipcode".equals(key) &&
|
||||||
|
"98011".equals(valueNode.asText());
|
||||||
|
foundDeleteFlag |= "delete".equals(opName) &&
|
||||||
|
"flag".equals(key) &&
|
||||||
|
(valueNode == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundInsertName && foundUpdateZipcode && foundDeleteFlag;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
.thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
DaprStateAsyncProvider provider = new DaprStateAsyncProvider(daprAsyncClient, SERIALIZER);
|
||||||
|
provider.apply("MyActor",
|
||||||
|
"123",
|
||||||
|
createInsertChange("name", "Jon Doe"),
|
||||||
|
createUpdateChange("zipcode", "98011"),
|
||||||
|
createDeleteChange("flag"))
|
||||||
|
.block();
|
||||||
|
|
||||||
|
verify(daprAsyncClient).saveStateTransactionally(eq("MyActor"), eq("123"), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void happyCaseLoad() {
|
||||||
|
AppToDaprAsyncClient daprAsyncClient = mock(AppToDaprAsyncClient.class);
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("name")))
|
||||||
|
.thenReturn(Mono.just("Jon Doe"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("zipcode")))
|
||||||
|
.thenReturn(Mono.just("98021"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("goals")))
|
||||||
|
.thenReturn(Mono.just("98"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("balance")))
|
||||||
|
.thenReturn(Mono.just("46.55"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("active")))
|
||||||
|
.thenReturn(Mono.just("true"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("customer")))
|
||||||
|
.thenReturn(Mono.just("{ \"id\": 1000, \"name\": \"Roxane\"}"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("anotherCustomer")))
|
||||||
|
.thenReturn(Mono.just("{ \"id\": 2000, \"name\": \"Max\"}"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("nullCustomer")))
|
||||||
|
.thenReturn(Mono.just(""));
|
||||||
|
|
||||||
|
DaprStateAsyncProvider provider = new DaprStateAsyncProvider(daprAsyncClient, SERIALIZER);
|
||||||
|
|
||||||
|
Assert.assertEquals("Jon Doe",
|
||||||
|
provider.load("MyActor", "123", "name", String.class).block());
|
||||||
|
Assert.assertEquals("98021",
|
||||||
|
provider.load("MyActor", "123", "zipcode", String.class).block());
|
||||||
|
Assert.assertEquals(98,
|
||||||
|
(int) provider.load("MyActor", "123", "goals", int.class).block());
|
||||||
|
Assert.assertEquals(98,
|
||||||
|
(int) provider.load("MyActor", "123", "goals", int.class).block());
|
||||||
|
Assert.assertEquals(46.55,
|
||||||
|
(double) provider.load("MyActor", "123", "balance", double.class).block(),
|
||||||
|
EPSILON);
|
||||||
|
Assert.assertEquals(true,
|
||||||
|
(boolean) provider.load("MyActor", "123", "active", boolean.class).block());
|
||||||
|
Assert.assertEquals(new Customer().setId(1000).setName("Roxane"),
|
||||||
|
provider.load("MyActor", "123", "customer", Customer.class).block());
|
||||||
|
Assert.assertNotEquals(new Customer().setId(1000).setName("Roxane"),
|
||||||
|
provider.load("MyActor", "123", "anotherCustomer", Customer.class).block());
|
||||||
|
Assert.assertNull(provider.load("MyActor", "123", "nullCustomer", Customer.class).block());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void happyCaseContains() {
|
||||||
|
AppToDaprAsyncClient daprAsyncClient = mock(AppToDaprAsyncClient.class);
|
||||||
|
|
||||||
|
// Keys that exists.
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("name")))
|
||||||
|
.thenReturn(Mono.just("Jon Doe"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("zipcode")))
|
||||||
|
.thenReturn(Mono.just("98021"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("goals")))
|
||||||
|
.thenReturn(Mono.just("98"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("balance")))
|
||||||
|
.thenReturn(Mono.just("46.55"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("active")))
|
||||||
|
.thenReturn(Mono.just("true"));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("customer")))
|
||||||
|
.thenReturn(Mono.just("{ \"id\": \"3000\", \"name\": \"Ely\" }"));
|
||||||
|
|
||||||
|
// Keys that do not exist.
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("Does not exist")))
|
||||||
|
.thenReturn(Mono.just(""));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq("NAME")))
|
||||||
|
.thenReturn(Mono.just(""));
|
||||||
|
when(daprAsyncClient
|
||||||
|
.getState(any(), any(), eq(null)))
|
||||||
|
.thenReturn(Mono.just(""));
|
||||||
|
|
||||||
|
DaprStateAsyncProvider provider = new DaprStateAsyncProvider(daprAsyncClient, SERIALIZER);
|
||||||
|
|
||||||
|
Assert.assertTrue(provider.contains("MyActor", "123", "name").block());
|
||||||
|
Assert.assertFalse(provider.contains("MyActor", "123", "NAME").block());
|
||||||
|
Assert.assertTrue(provider.contains("MyActor", "123", "zipcode").block());
|
||||||
|
Assert.assertTrue(provider.contains("MyActor", "123", "goals").block());
|
||||||
|
Assert.assertTrue(provider.contains("MyActor", "123", "balance").block());
|
||||||
|
Assert.assertTrue(provider.contains("MyActor", "123", "active").block());
|
||||||
|
Assert.assertTrue(provider.contains("MyActor", "123", "customer").block());
|
||||||
|
Assert.assertFalse(provider.contains("MyActor", "123", "Does not exist").block());
|
||||||
|
Assert.assertFalse(provider.contains("MyActor", "123", null).block());
|
||||||
|
}
|
||||||
|
|
||||||
|
private final <T> ActorStateChange<T> createInsertChange(String name, T value) {
|
||||||
|
return new ActorStateChange(name, value, ActorStateChangeKind.ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final <T> ActorStateChange<T> createUpdateChange(String name, T value) {
|
||||||
|
return new ActorStateChange(name, value, ActorStateChangeKind.UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final <T> ActorStateChange<T> createDeleteChange(String name) {
|
||||||
|
return new ActorStateChange(name, null, ActorStateChangeKind.REMOVE);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue