DATAREDIS-849 - Add support for immutable objects.

We now support immutable objects for saving (e.g. object without a provided Id) and loading (i.e. persistence constructor declares a subset of properties). New instances are created using wither methods/Kotlin copy(…) methods if an immutable object requires association with an Id.

Association of the Id to its object moved from RedisKeyValueAdapter to RedisKeyValueTemplate.
This commit is contained in:
Mark Paluch
2018-07-03 16:46:00 +02:00
committed by Oliver Gierke
parent 3defab118e
commit 322cfabb17
7 changed files with 140 additions and 21 deletions

View File

@@ -19,8 +19,10 @@ import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.number.IsCloseTo.*;
import static org.junit.Assert.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Wither;
import java.util.ArrayList;
import java.util.Arrays;
@@ -805,6 +807,33 @@ public class RedisKeyValueTemplateTests {
assertThat(target.get().ttl, is(-1L));
}
@Test // DATAREDIS-849
public void shouldWriteImmutableType() {
ImmutableObject source = new ImmutableObject().withValue("foo").withTtl(1234L);
ImmutableObject inserted = template.insert(source);
assertThat(source.id, is(nullValue()));
assertThat(inserted.id, is(notNullValue()));
}
@Test // DATAREDIS-849
public void shouldReadImmutableType() {
ImmutableObject source = new ImmutableObject().withValue("foo").withTtl(1234L);
ImmutableObject inserted = template.insert(source);
Optional<ImmutableObject> loaded = template.findById(inserted.id, ImmutableObject.class);
assertThat(loaded.isPresent(), is(true));
ImmutableObject immutableObject = loaded.get();
assertThat(immutableObject.id, is(inserted.id));
assertThat(immutableObject.ttl, is(notNullValue()));
assertThat(immutableObject.value, is(inserted.value));
}
@EqualsAndHashCode
@RedisHash("template-test-type-mapping")
static class VariousTypes {
@@ -929,4 +958,20 @@ public class RedisKeyValueTemplateTests {
String value;
@TimeToLive int ttl;
}
@Data
@Wither
@AllArgsConstructor
static class ImmutableObject {
final @Id String id;
final String value;
final @TimeToLive Long ttl;
ImmutableObject() {
this.id = null;
this.value = null;
this.ttl = null;
}
}
}

View File

@@ -54,7 +54,7 @@ public class RedisRepositoryClusterIntegrationTests extends RedisRepositoryInteg
@EnableRedisRepositories(considerNestedRepositories = true, indexConfiguration = MyIndexConfiguration.class,
keyspaceConfiguration = MyKeyspaceConfiguration.class,
includeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = { PersonRepository.class, CityRepository.class }) })
classes = { PersonRepository.class, CityRepository.class, ImmutableObjectRepository.class }) })
static class Config {
@Bean

View File

@@ -19,6 +19,8 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import lombok.Data;
import lombok.Value;
import lombok.experimental.Wither;
import java.util.Arrays;
import java.util.Collections;
@@ -60,6 +62,7 @@ public abstract class RedisRepositoryIntegrationTestBase {
@Autowired PersonRepository repo;
@Autowired CityRepository cityRepo;
@Autowired ImmutableObjectRepository immutableObjectRepo;
@Autowired KeyValueTemplate kvTemplate;
@Before
@@ -403,6 +406,37 @@ public abstract class RedisRepositoryIntegrationTestBase {
assertThat(result, not(hasItems(p1)));
}
@Test // DATAREDIS-849
public void shouldReturnNewObjectInstanceOnImmutableSave() {
Immutable object = new Immutable(null, "Walter", new Immutable("heisenberg", "White", null));
Immutable saved = immutableObjectRepo.save(object);
assertThat(object.id, is(nullValue()));
assertThat(saved.id, is(notNullValue()));
}
@Test // DATAREDIS-849
public void shouldReturnNewObjectInstanceOnImmutableSaveAll() {
Immutable object = new Immutable(null, "Walter", new Immutable("heisenberg", "White", null));
List<Immutable> saved = (List) immutableObjectRepo.saveAll(Collections.singleton(object));
assertThat(object.id, is(nullValue()));
assertThat(saved.get(0).id, is(notNullValue()));
}
@Test // DATAREDIS-849
public void shouldProperlyReadNestedImmutableObject() {
Immutable nested = new Immutable("heisenberg", "White", null);
Immutable object = new Immutable(null, "Walter", nested);
Immutable saved = immutableObjectRepo.save(object);
Immutable loaded = immutableObjectRepo.findById(saved.id).get();
assertThat(loaded.nested, is(nested));
}
public static interface PersonRepository
extends PagingAndSortingRepository<Person, String>, QueryByExampleExecutor<Person> {
@@ -434,11 +468,13 @@ public abstract class RedisRepositoryIntegrationTestBase {
<S extends Person> List<S> findAll(Example<S> example);
}
public static interface CityRepository extends CrudRepository<City, String> {
public interface CityRepository extends CrudRepository<City, String> {
List<City> findByLocationNear(Point point, Distance distance);
}
public interface ImmutableObjectRepository extends CrudRepository<Immutable, String> {}
/**
* Custom Redis {@link IndexConfiguration} forcing index of {@link Person#lastname}.
*
@@ -493,4 +529,14 @@ public abstract class RedisRepositoryIntegrationTestBase {
@GeoIndexed Point location;
}
@Value
@Wither
public static class Immutable {
@Id String id;
String name;
Immutable nested;
}
}

View File

@@ -56,7 +56,7 @@ public class RedisRepositoryIntegrationTests extends RedisRepositoryIntegrationT
@EnableRedisRepositories(considerNestedRepositories = true, indexConfiguration = MyIndexConfiguration.class,
keyspaceConfiguration = MyKeyspaceConfiguration.class,
includeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = { PersonRepository.class, CityRepository.class }) })
classes = { PersonRepository.class, CityRepository.class, ImmutableObjectRepository.class }) })
static class Config {