diff --git a/redis/reactive/pom.xml b/redis/reactive/pom.xml
index 2b89bca7..670f7293 100644
--- a/redis/reactive/pom.xml
+++ b/redis/reactive/pom.xml
@@ -29,6 +29,11 @@
lettuce-core
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
io.projectreactor
reactor-test
diff --git a/redis/reactive/src/test/java/example/springdata/redis/EmailAddress.java b/redis/reactive/src/test/java/example/springdata/redis/EmailAddress.java
new file mode 100644
index 00000000..6a8e2d49
--- /dev/null
+++ b/redis/reactive/src/test/java/example/springdata/redis/EmailAddress.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017 the original author or 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 example.springdata.redis;
+
+import lombok.RequiredArgsConstructor;
+import lombok.Value;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+
+/**
+ * Example value object.
+ *
+ * @author Mark Paluch
+ */
+@Value
+@RequiredArgsConstructor
+@JsonTypeInfo(use = Id.CLASS, property = "_type")
+public class EmailAddress {
+ final String address;
+}
diff --git a/redis/reactive/src/test/java/example/springdata/redis/Person.java b/redis/reactive/src/test/java/example/springdata/redis/Person.java
new file mode 100644
index 00000000..39697286
--- /dev/null
+++ b/redis/reactive/src/test/java/example/springdata/redis/Person.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 the original author or 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 example.springdata.redis;
+
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Example value object.
+ *
+ * @author Mark Paluch
+ */
+@Data
+@RequiredArgsConstructor
+public class Person {
+
+ final String firstname;
+ final String lastname;
+}
diff --git a/redis/reactive/src/test/java/example/springdata/redis/RedisTestConfiguration.java b/redis/reactive/src/test/java/example/springdata/redis/RedisTestConfiguration.java
index 41edf738..fc594303 100644
--- a/redis/reactive/src/test/java/example/springdata/redis/RedisTestConfiguration.java
+++ b/redis/reactive/src/test/java/example/springdata/redis/RedisTestConfiguration.java
@@ -24,7 +24,11 @@ import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.RedisSerializationContext.RedisSerializationContextBuilder;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author Mark Paluch
@@ -44,6 +48,39 @@ public class RedisTestConfiguration {
return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
}
+ /**
+ * Configures a {@link ReactiveRedisTemplate} with {@link String} keys and a typed
+ * {@link Jackson2JsonRedisSerializer}.
+ */
+ @Bean
+ public ReactiveRedisTemplate reactiveJsonPersonRedisTemplate(
+ ReactiveRedisConnectionFactory connectionFactory) {
+
+ Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Person.class);
+ RedisSerializationContextBuilder builder = RedisSerializationContext
+ .newSerializationContext(new StringRedisSerializer());
+
+ RedisSerializationContext serializationContext = builder.value(serializer).build();
+
+ return new ReactiveRedisTemplate<>(connectionFactory, serializationContext);
+ }
+
+ /**
+ * Configures a {@link ReactiveRedisTemplate} with {@link String} keys and {@link GenericJackson2JsonRedisSerializer}.
+ */
+ @Bean
+ public ReactiveRedisTemplate reactiveJsonObjectRedisTemplate(
+ ReactiveRedisConnectionFactory connectionFactory) {
+
+ RedisSerializationContextBuilder builder = RedisSerializationContext
+ .newSerializationContext(new StringRedisSerializer());
+
+ RedisSerializationContext serializationContext = builder
+ .value(new GenericJackson2JsonRedisSerializer("_type")).build();
+
+ return new ReactiveRedisTemplate<>(connectionFactory, serializationContext);
+ }
+
/**
* Clear database before shut down.
*/
diff --git a/redis/reactive/src/test/java/example/springdata/redis/operations/JacksonJsonTests.java b/redis/reactive/src/test/java/example/springdata/redis/operations/JacksonJsonTests.java
new file mode 100644
index 00000000..752e79c5
--- /dev/null
+++ b/redis/reactive/src/test/java/example/springdata/redis/operations/JacksonJsonTests.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2017 the original author or 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 example.springdata.redis.operations;
+
+import example.springdata.redis.EmailAddress;
+import example.springdata.redis.Person;
+import example.springdata.redis.RedisTestConfiguration;
+import example.springdata.redis.test.util.RequiresRedisServer;
+import lombok.extern.slf4j.Slf4j;
+import reactor.core.publisher.Flux;
+import reactor.test.StepVerifier;
+
+import java.nio.ByteBuffer;
+
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
+import org.springframework.data.redis.core.ReactiveRedisOperations;
+import org.springframework.data.redis.util.ByteUtils;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Show usage of reactive Template API on Redis lists using {@link ReactiveRedisOperations} with Jackson serialization.
+ *
+ * @author Mark Paluch
+ */
+@Slf4j
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = RedisTestConfiguration.class)
+public class JacksonJsonTests {
+
+ // we only want to run this tests when redis is up an running
+ public static @ClassRule RequiresRedisServer requiresServer = RequiresRedisServer.onLocalhost();
+
+ @Autowired ReactiveRedisOperations typedOperations;
+
+ @Autowired ReactiveRedisOperations genericOperations;
+
+ /**
+ * {@link ReactiveRedisOperations} using {@link String} keys and {@link Person} values serialized via
+ * {@link org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer} to JSON without additional type
+ * hints.
+ *
+ * @see RedisTestConfiguration#reactiveJsonPersonRedisTemplate(ReactiveRedisConnectionFactory)
+ */
+ @Test
+ public void shouldWriteAndReadPerson() {
+
+ StepVerifier.create(typedOperations.opsForValue().set("homer", new Person("Homer", "Simpson"))) //
+ .expectNext(true) //
+ .verifyComplete();
+
+ Flux get = typedOperations.execute(conn -> conn.stringCommands().get(ByteBuffer.wrap("homer".getBytes()))) //
+ .map(ByteUtils::getBytes) //
+ .map(String::new);
+
+ StepVerifier.create(get) //
+ .expectNext("{\"firstname\":\"Homer\",\"lastname\":\"Simpson\"}") //
+ .verifyComplete();
+
+ StepVerifier.create(typedOperations.opsForValue().get("homer")) //
+ .expectNext(new Person("Homer", "Simpson")) //
+ .verifyComplete();
+ }
+
+ /**
+ * {@link ReactiveRedisOperations} using {@link String} keys and {@link Object} values serialized via
+ * {@link org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer} to JSON with additional type
+ * hints. This example uses the non-final type {@link Person} using its FQCN as type identifier.
+ *
+ * @see RedisTestConfiguration#reactiveJsonObjectRedisTemplate(ReactiveRedisConnectionFactory)
+ */
+ @Test
+ public void shouldWriteAndReadPersonObject() {
+
+ StepVerifier.create(genericOperations.opsForValue().set("homer", new Person("Homer", "Simpson"))) //
+ .expectNext(true) //
+ .verifyComplete();
+
+ Flux get = genericOperations.execute(conn -> conn.stringCommands().get(ByteBuffer.wrap("homer".getBytes()))) //
+ .map(ByteUtils::getBytes) //
+ .map(String::new);
+
+ StepVerifier.create(get) //
+ .expectNext("{\"_type\":\"example.springdata.redis.Person\",\"firstname\":\"Homer\",\"lastname\":\"Simpson\"}") //
+ .verifyComplete();
+
+ StepVerifier.create(genericOperations.opsForValue().get("homer")) //
+ .expectNext(new Person("Homer", "Simpson")) //
+ .verifyComplete();
+ }
+
+ /**
+ * {@link ReactiveRedisOperations} using {@link String} keys and {@link Object} values serialized via
+ * {@link org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer} to JSON with additional type
+ * hints. This example uses the final type {@link example.springdata.redis.EmailAddress} using configuration from
+ * {@link com.fasterxml.jackson.annotation.JsonTypeInfo} as type identifier.
+ *
+ * @see RedisTestConfiguration#reactiveJsonObjectRedisTemplate(ReactiveRedisConnectionFactory)
+ */
+ @Test
+ public void shouldWriteAndReadEmailObject() {
+
+ StepVerifier.create(genericOperations.opsForValue().set("mail", new EmailAddress("homer@the-simpsons.com"))) //
+ .expectNext(true) //
+ .verifyComplete();
+
+ Flux get = genericOperations.execute(conn -> conn.stringCommands().get(ByteBuffer.wrap("mail".getBytes()))) //
+ .map(ByteUtils::getBytes) //
+ .map(String::new);
+
+ StepVerifier.create(get) //
+ .expectNext("{\"_type\":\"example.springdata.redis.EmailAddress\",\"address\":\"homer@the-simpsons.com\"}") //
+ .verifyComplete();
+
+ StepVerifier.create(genericOperations.opsForValue().get("mail")) //
+ .expectNext(new EmailAddress("homer@the-simpsons.com")) //
+ .verifyComplete();
+ }
+}