/* * Copyright 2015-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 org.springframework.data.redis.core.convert; import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.contains; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static org.springframework.data.redis.core.convert.ConversionTestEntities.*; import static org.springframework.data.redis.test.util.IsBucketMatcher.*; import java.io.Serializable; import java.nio.charset.Charset; import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Period; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.*; import org.hamcrest.core.IsEqual; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.redis.core.PartialUpdate; import org.springframework.data.redis.core.convert.KeyspaceConfiguration.KeyspaceSettings; import org.springframework.data.redis.core.convert.ConversionTestEntities.*; import org.springframework.data.redis.core.mapping.RedisMappingContext; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.util.StringUtils; import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; import com.fasterxml.jackson.databind.ObjectMapper; /** * Unit tests for {@link MappingRedisConverter}. * * @author Christoph Strobl * @author Greg Turnquist * @author Mark Paluch */ @RunWith(MockitoJUnitRunner.class) public class MappingRedisConverterUnitTests { public @Rule ExpectedException exception = ExpectedException.none(); @Mock ReferenceResolver resolverMock; MappingRedisConverter converter; Person rand; @Before public void setUp() { converter = new MappingRedisConverter(new RedisMappingContext(), null, resolverMock); converter.afterPropertiesSet(); rand = new Person(); } @Test // DATAREDIS-425 public void writeAppendsTypeHintForRootCorrectly() { assertThat(write(rand).getBucket(), isBucket().containingTypeHint("_class", Person.class)); } @Test // DATAREDIS-425 public void writeAppendsKeyCorrectly() { rand.id = "1"; assertThat(write(rand).getId(), is((Serializable) "1")); } @Test // DATAREDIS-425 public void writeAppendsKeyCorrectlyWhenThereIsAnAdditionalIdFieldInNestedElement() { AddressWithId address = new AddressWithId(); address.id = "tear"; address.city = "Tear"; rand.id = "1"; rand.address = address; RedisData data = write(rand); assertThat(data.getId(), is((Serializable) "1")); assertThat(data.getBucket(), isBucket().containingUtf8String("address.id", "tear")); } @Test // DATAREDIS-425 public void writeDoesNotAppendPropertiesWithNullValues() { rand.firstname = "rand"; assertThat(write(rand).getBucket(), isBucket().without("lastname")); } @Test // DATAREDIS-425 public void writeDoesNotAppendPropertiesWithEmptyCollections() { rand.firstname = "rand"; assertThat(write(rand).getBucket(), isBucket().without("nicknames")); } @Test // DATAREDIS-425 public void writeAppendsSimpleRootPropertyCorrectly() { rand.firstname = "nynaeve"; assertThat(write(rand).getBucket(), isBucket().containingUtf8String("firstname", "nynaeve")); } @Test // DATAREDIS-425 public void writeAppendsListOfSimplePropertiesCorrectly() { rand.nicknames = Arrays.asList("dragon reborn", "lews therin"); RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingUtf8String("nicknames.[0]", "dragon reborn") .containingUtf8String("nicknames.[1]", "lews therin")); } @Test // DATAREDIS-425 public void writeAppendsComplexObjectCorrectly() { Address address = new Address(); address.city = "two rivers"; address.country = "andora"; rand.address = address; RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingUtf8String("address.city", "two rivers") .containingUtf8String("address.country", "andora")); } @Test // DATAREDIS-425 public void writeAppendsListOfComplexObjectsCorrectly() { Person mat = new Person(); mat.firstname = "mat"; mat.nicknames = Arrays.asList("prince of the ravens"); Person perrin = new Person(); perrin.firstname = "perrin"; perrin.address = new Address(); perrin.address.city = "two rivers"; rand.coworkers = Arrays.asList(mat, perrin); rand.id = UUID.randomUUID().toString(); rand.firstname = "rand"; RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingUtf8String("coworkers.[0].firstname", "mat") // .containingUtf8String("coworkers.[0].nicknames.[0]", "prince of the ravens") // .containingUtf8String("coworkers.[1].firstname", "perrin") // .containingUtf8String("coworkers.[1].address.city", "two rivers")); } @Test // DATAREDIS-425 public void writeDoesNotAddClassTypeInformationCorrectlyForMatchingTypes() { Address address = new Address(); address.city = "two rivers"; rand.address = address; RedisData target = write(rand); assertThat(target.getBucket(), isBucket().without("address._class")); } @Test // DATAREDIS-425 public void writeAddsClassTypeInformationCorrectlyForNonMatchingTypes() { AddressWithPostcode address = new AddressWithPostcode(); address.city = "two rivers"; address.postcode = "1234"; rand.address = address; RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingTypeHint("address._class", AddressWithPostcode.class)); } @Test // DATAREDIS-425 public void readConsidersClassTypeInformationCorrectlyForNonMatchingTypes() { Map<String, String> map = new HashMap<String, String>(); map.put("address._class", AddressWithPostcode.class.getName()); map.put("address.postcode", "1234"); Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target.address, instanceOf(AddressWithPostcode.class)); } @Test // DATAREDIS-425 public void writeAddsClassTypeInformationCorrectlyForNonMatchingTypesInCollections() { Person mat = new TaVeren(); mat.firstname = "mat"; rand.coworkers = Arrays.asList(mat); RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingTypeHint("coworkers.[0]._class", TaVeren.class)); } @Test // DATAREDIS-425 public void readConvertsSimplePropertiesCorrectly() { RedisData rdo = new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("firstname", "rand"))); assertThat(converter.read(Person.class, rdo).firstname, is("rand")); } @Test // DATAREDIS-425 public void readConvertsListOfSimplePropertiesCorrectly() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("nicknames.[0]", "dragon reborn"); map.put("nicknames.[1]", "lews therin"); RedisData rdo = new RedisData(Bucket.newBucketFromStringMap(map)); assertThat(converter.read(Person.class, rdo).nicknames, contains("dragon reborn", "lews therin")); } @Test // DATAREDIS-425 public void readConvertsUnorderedListOfSimplePropertiesCorrectly() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("nicknames.[9]", "car'a'carn"); map.put("nicknames.[10]", "lews therin"); map.put("nicknames.[1]", "dragon reborn"); RedisData rdo = new RedisData(Bucket.newBucketFromStringMap(map)); assertThat(converter.read(Person.class, rdo).nicknames, contains("dragon reborn", "car'a'carn", "lews therin")); } @Test // DATAREDIS-425 public void readComplexPropertyCorrectly() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("address.city", "two rivers"); map.put("address.country", "andor"); RedisData rdo = new RedisData(Bucket.newBucketFromStringMap(map)); Person target = converter.read(Person.class, rdo); assertThat(target.address, notNullValue()); assertThat(target.address.city, is("two rivers")); assertThat(target.address.country, is("andor")); } @Test // DATAREDIS-425 public void readListComplexPropertyCorrectly() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("coworkers.[0].firstname", "mat"); map.put("coworkers.[0].nicknames.[0]", "prince of the ravens"); map.put("coworkers.[0].nicknames.[1]", "gambler"); map.put("coworkers.[1].firstname", "perrin"); map.put("coworkers.[1].address.city", "two rivers"); RedisData rdo = new RedisData(Bucket.newBucketFromStringMap(map)); Person target = converter.read(Person.class, rdo); assertThat(target.coworkers, notNullValue()); assertThat(target.coworkers.get(0).firstname, is("mat")); assertThat(target.coworkers.get(0).nicknames, notNullValue()); assertThat(target.coworkers.get(0).nicknames.get(0), is("prince of the ravens")); assertThat(target.coworkers.get(0).nicknames.get(1), is("gambler")); assertThat(target.coworkers.get(1).firstname, is("perrin")); assertThat(target.coworkers.get(1).address.city, is("two rivers")); } @Test // DATAREDIS-425 public void readUnorderedListOfComplexPropertyCorrectly() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("coworkers.[10].firstname", "perrin"); map.put("coworkers.[10].address.city", "two rivers"); map.put("coworkers.[1].firstname", "mat"); map.put("coworkers.[1].nicknames.[1]", "gambler"); map.put("coworkers.[1].nicknames.[0]", "prince of the ravens"); RedisData rdo = new RedisData(Bucket.newBucketFromStringMap(map)); Person target = converter.read(Person.class, rdo); assertThat(target.coworkers, notNullValue()); assertThat(target.coworkers.get(0).firstname, is("mat")); assertThat(target.coworkers.get(0).nicknames, notNullValue()); assertThat(target.coworkers.get(0).nicknames.get(0), is("prince of the ravens")); assertThat(target.coworkers.get(0).nicknames.get(1), is("gambler")); assertThat(target.coworkers.get(1).firstname, is("perrin")); assertThat(target.coworkers.get(1).address.city, is("two rivers")); } @Test // DATAREDIS-425 public void readListComplexPropertyCorrectlyAndConsidersClassTypeInformation() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("coworkers.[0]._class", TaVeren.class.getName()); map.put("coworkers.[0].firstname", "mat"); RedisData rdo = new RedisData(Bucket.newBucketFromStringMap(map)); Person target = converter.read(Person.class, rdo); assertThat(target.coworkers, notNullValue()); assertThat(target.coworkers.get(0), instanceOf(TaVeren.class)); assertThat(target.coworkers.get(0).firstname, is("mat")); } @Test // DATAREDIS-425 public void writeAppendsMapWithSimpleKeyCorrectly() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("hair-color", "red"); map.put("eye-color", "grey"); rand.physicalAttributes = map; RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingUtf8String("physicalAttributes.[hair-color]", "red") // .containingUtf8String("physicalAttributes.[eye-color]", "grey")); } @Test // DATAREDIS-425 public void writeAppendsMapWithSimpleKeyOnNestedObjectCorrectly() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("hair-color", "red"); map.put("eye-color", "grey"); rand.coworkers = new ArrayList<Person>(); rand.coworkers.add(new Person()); rand.coworkers.get(0).physicalAttributes = map; RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingUtf8String("coworkers.[0].physicalAttributes.[hair-color]", "red") // .containingUtf8String("coworkers.[0].physicalAttributes.[eye-color]", "grey")); } @Test // DATAREDIS-425 public void readSimpleMapValuesCorrectly() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("physicalAttributes.[hair-color]", "red"); map.put("physicalAttributes.[eye-color]", "grey"); RedisData rdo = new RedisData(Bucket.newBucketFromStringMap(map)); Person target = converter.read(Person.class, rdo); assertThat(target.physicalAttributes, notNullValue()); assertThat(target.physicalAttributes.get("hair-color"), is("red")); assertThat(target.physicalAttributes.get("eye-color"), is("grey")); } @Test // DATAREDIS-425 public void writeAppendsMapWithComplexObjectsCorrectly() { Map<String, Person> map = new LinkedHashMap<String, Person>(); Person janduin = new Person(); janduin.firstname = "janduin"; map.put("father", janduin); Person tam = new Person(); tam.firstname = "tam"; map.put("step-father", tam); rand.relatives = map; RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingUtf8String("relatives.[father].firstname", "janduin") // .containingUtf8String("relatives.[step-father].firstname", "tam")); } @Test // DATAREDIS-425 public void readMapWithComplexObjectsCorrectly() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("relatives.[father].firstname", "janduin"); map.put("relatives.[step-father].firstname", "tam"); Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target.relatives, notNullValue()); assertThat(target.relatives.get("father"), notNullValue()); assertThat(target.relatives.get("father").firstname, is("janduin")); assertThat(target.relatives.get("step-father"), notNullValue()); assertThat(target.relatives.get("step-father").firstname, is("tam")); } @Test // DATAREDIS-425 public void writeAppendsClassTypeInformationCorrectlyForMapWithComplexObjects() { Map<String, Person> map = new LinkedHashMap<String, Person>(); Person lews = new TaVeren(); lews.firstname = "lews"; map.put("previous-incarnation", lews); rand.relatives = map; RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingTypeHint("relatives.[previous-incarnation]._class", TaVeren.class)); } @Test // DATAREDIS-425 public void readConsidersClassTypeInformationCorrectlyForMapWithComplexObjects() { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("relatives.[previous-incarnation]._class", TaVeren.class.getName()); map.put("relatives.[previous-incarnation].firstname", "lews"); Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target.relatives.get("previous-incarnation"), notNullValue()); assertThat(target.relatives.get("previous-incarnation"), instanceOf(TaVeren.class)); assertThat(target.relatives.get("previous-incarnation").firstname, is("lews")); } @Test // DATAREDIS-425 public void writesIntegerValuesCorrectly() { rand.age = 20; assertThat(write(rand).getBucket(), isBucket().containingUtf8String("age", "20")); } @Test // DATAREDIS-425 public void writesLocalDateTimeValuesCorrectly() { rand.localDateTime = LocalDateTime.parse("2016-02-19T10:18:01"); assertThat(write(rand).getBucket(), isBucket().containingUtf8String("localDateTime", "2016-02-19T10:18:01")); } @Test // DATAREDIS-425 public void readsLocalDateTimeValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("localDateTime", "2016-02-19T10:18:01")))); assertThat(target.localDateTime, is(LocalDateTime.parse("2016-02-19T10:18:01"))); } @Test // DATAREDIS-425 public void writesLocalDateValuesCorrectly() { rand.localDate = LocalDate.parse("2016-02-19"); assertThat(write(rand).getBucket(), isBucket().containingUtf8String("localDate", "2016-02-19")); } @Test // DATAREDIS-425 public void readsLocalDateValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("localDate", "2016-02-19")))); assertThat(target.localDate, is(LocalDate.parse("2016-02-19"))); } @Test // DATAREDIS-425 public void writesLocalTimeValuesCorrectly() { rand.localTime = LocalTime.parse("11:12:13"); assertThat(write(rand).getBucket(), isBucket().containingUtf8String("localTime", "11:12:13")); } @Test // DATAREDIS-425 public void readsLocalTimeValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("localTime", "11:12")))); assertThat(target.localTime, is(LocalTime.parse("11:12:00"))); } @Test // DATAREDIS-425 public void writesZonedDateTimeValuesCorrectly() { rand.zonedDateTime = ZonedDateTime.parse("2007-12-03T10:15:30+01:00[Europe/Paris]"); assertThat(write(rand).getBucket(), isBucket().containingUtf8String("zonedDateTime", "2007-12-03T10:15:30+01:00[Europe/Paris]")); } @Test // DATAREDIS-425 public void readsZonedDateTimeValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket .newBucketFromStringMap(Collections.singletonMap("zonedDateTime", "2007-12-03T10:15:30+01:00[Europe/Paris]")))); assertThat(target.zonedDateTime, is(ZonedDateTime.parse("2007-12-03T10:15:30+01:00[Europe/Paris]"))); } @Test // DATAREDIS-425 public void writesInstantValuesCorrectly() { rand.instant = Instant.parse("2007-12-03T10:15:30.01Z"); assertThat(write(rand).getBucket(), isBucket().containingUtf8String("instant", "2007-12-03T10:15:30.010Z")); } @Test // DATAREDIS-425 public void readsInstantValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("instant", "2007-12-03T10:15:30.01Z")))); assertThat(target.instant, is(Instant.parse("2007-12-03T10:15:30.01Z"))); } @Test // DATAREDIS-425 public void writesZoneIdValuesCorrectly() { rand.zoneId = ZoneId.of("Europe/Paris"); assertThat(write(rand).getBucket(), isBucket().containingUtf8String("zoneId", "Europe/Paris")); } @Test // DATAREDIS-425 public void readsZoneIdValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("zoneId", "Europe/Paris")))); assertThat(target.zoneId, is(ZoneId.of("Europe/Paris"))); } @Test // DATAREDIS-425 public void writesDurationValuesCorrectly() { rand.duration = Duration.parse("P2DT3H4M"); assertThat(write(rand).getBucket(), isBucket().containingUtf8String("duration", "PT51H4M")); } @Test // DATAREDIS-425 public void readsDurationValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("duration", "PT51H4M")))); assertThat(target.duration, is(Duration.parse("P2DT3H4M"))); } @Test // DATAREDIS-425 public void writesPeriodValuesCorrectly() { rand.period = Period.parse("P1Y2M25D"); assertThat(write(rand).getBucket(), isBucket().containingUtf8String("period", "P1Y2M25D")); } @Test // DATAREDIS-425 public void readsPeriodValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("period", "P1Y2M25D")))); assertThat(target.period, is(Period.parse("P1Y2M25D"))); } @Test // DATAREDIS-425, DATAREDIS-593 public void writesEnumValuesCorrectly() { rand.gender = Gender.FEMALE; assertThat(write(rand).getBucket(), isBucket().containingUtf8String("gender", "FEMALE")); } @Test // DATAREDIS-425, DATAREDIS-593 public void readsEnumValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("gender", "FEMALE")))); assertThat(target.gender, is(Gender.FEMALE)); } @Test // DATAREDIS-425 public void writesBooleanValuesCorrectly() { rand.alive = Boolean.TRUE; assertThat(write(rand).getBucket(), isBucket().containingUtf8String("alive", "1")); } @Test // DATAREDIS-425 public void readsBooleanValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("alive", "1")))); assertThat(target.alive, is(Boolean.TRUE)); } @Test // DATAREDIS-425 public void readsStringBooleanValuesCorrectly() { Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("alive", "true")))); assertThat(target.alive, is(Boolean.TRUE)); } @Test // DATAREDIS-425 public void writesDateValuesCorrectly() { Calendar cal = Calendar.getInstance(); cal.set(1978, 10, 25); rand.birthdate = cal.getTime(); assertThat(write(rand).getBucket(), isBucket().containingDateAsMsec("birthdate", rand.birthdate)); } @Test // DATAREDIS-425 public void readsDateValuesCorrectly() { Calendar cal = Calendar.getInstance(); cal.set(1978, 10, 25); Date date = cal.getTime(); Person target = converter.read(Person.class, new RedisData( Bucket.newBucketFromStringMap(Collections.singletonMap("birthdate", Long.valueOf(date.getTime()).toString())))); assertThat(target.birthdate, is(date)); } @Test // DATAREDIS-425 public void writeSingleReferenceOnRootCorrectly() { Location location = new Location(); location.id = "1"; location.name = "tar valon"; rand.location = location; RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingUtf8String("location", "locations:1") // .without("location.id") // .without("location.name")); } @Test // DATAREDIS-425 public void readLoadsReferenceDataOnRootCorrectly() { Location location = new Location(); location.id = "1"; location.name = "tar valon"; Map<String, String> locationMap = new LinkedHashMap<String, String>(); locationMap.put("id", location.id); locationMap.put("name", location.name); when(resolverMock.resolveReference(eq("1"), eq("locations"))) .thenReturn(Bucket.newBucketFromStringMap(locationMap).rawMap()); Map<String, String> map = new LinkedHashMap<String, String>(); map.put("location", "locations:1"); Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target.location, is(location)); } @Test // DATAREDIS-425 public void writeSingleReferenceOnNestedElementCorrectly() { Location location = new Location(); location.id = "1"; location.name = "tar valon"; Person egwene = new Person(); egwene.location = location; rand.coworkers = Collections.singletonList(egwene); RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingUtf8String("coworkers.[0].location", "locations:1") // .without("coworkers.[0].location.id") // .without("coworkers.[0].location.name")); } @Test // DATAREDIS-425 public void readLoadsReferenceDataOnNestedElementCorrectly() { Location location = new Location(); location.id = "1"; location.name = "tar valon"; Map<String, String> locationMap = new LinkedHashMap<String, String>(); locationMap.put("id", location.id); locationMap.put("name", location.name); when(resolverMock.resolveReference(eq("1"), eq("locations"))) .thenReturn(Bucket.newBucketFromStringMap(locationMap).rawMap()); Map<String, String> map = new LinkedHashMap<String, String>(); map.put("coworkers.[0].location", "locations:1"); Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target.coworkers.get(0).location, is(location)); } @Test // DATAREDIS-425 public void writeListOfReferencesOnRootCorrectly() { Location tarValon = new Location(); tarValon.id = "1"; tarValon.name = "tar valon"; Location falme = new Location(); falme.id = "2"; falme.name = "falme"; Location tear = new Location(); tear.id = "3"; tear.name = "city of tear"; rand.visited = Arrays.asList(tarValon, falme, tear); RedisData target = write(rand); assertThat(target.getBucket(), isBucket().containingUtf8String("visited.[0]", "locations:1") // .containingUtf8String("visited.[1]", "locations:2") // .containingUtf8String("visited.[2]", "locations:3")); } @Test // DATAREDIS-425 public void readLoadsListOfReferencesOnRootCorrectly() { Location tarValon = new Location(); tarValon.id = "1"; tarValon.name = "tar valon"; Location falme = new Location(); falme.id = "2"; falme.name = "falme"; Location tear = new Location(); tear.id = "3"; tear.name = "city of tear"; Map<String, String> tarValonMap = new LinkedHashMap<String, String>(); tarValonMap.put("id", tarValon.id); tarValonMap.put("name", tarValon.name); Map<String, String> falmeMap = new LinkedHashMap<String, String>(); falmeMap.put("id", falme.id); falmeMap.put("name", falme.name); Map<String, String> tearMap = new LinkedHashMap<String, String>(); tearMap.put("id", tear.id); tearMap.put("name", tear.name); Bucket.newBucketFromStringMap(tearMap).rawMap(); when(resolverMock.resolveReference(eq("1"), eq("locations"))) .thenReturn(Bucket.newBucketFromStringMap(tarValonMap).rawMap()); when(resolverMock.resolveReference(eq("2"), eq("locations"))) .thenReturn(Bucket.newBucketFromStringMap(falmeMap).rawMap()); when(resolverMock.resolveReference(eq("3"), eq("locations"))) .thenReturn(Bucket.newBucketFromStringMap(tearMap).rawMap()); Map<String, String> map = new LinkedHashMap<String, String>(); map.put("visited.[0]", "locations:1"); map.put("visited.[1]", "locations:2"); map.put("visited.[2]", "locations:3"); Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target.visited.get(0), is(tarValon)); assertThat(target.visited.get(1), is(falme)); assertThat(target.visited.get(2), is(tear)); } @Test // DATAREDIS-425 public void writeSetsAnnotatedTimeToLiveCorrectly() { ExpiringPerson birgitte = new ExpiringPerson(); birgitte.id = "birgitte"; birgitte.name = "Birgitte Silverbow"; assertThat(write(birgitte).getTimeToLive(), is(5L)); } @Test // DATAREDIS-425 public void writeDoesNotTTLWhenNotPresent() { Location tear = new Location(); tear.id = "tear"; tear.name = "Tear"; assertThat(write(tear).getTimeToLive(), nullValue()); } @Test // DATAREDIS-425 public void writeShouldConsiderKeyspaceConfiguration() { this.converter.getMappingContext().getMappingConfiguration().getKeyspaceConfiguration() .addKeyspaceSettings(new KeyspaceSettings(Address.class, "o_O")); Address address = new Address(); address.city = "Tear"; assertThat(write(address).getKeyspace(), is("o_O")); } @Test // DATAREDIS-425 public void writeShouldConsiderTimeToLiveConfiguration() { KeyspaceSettings assignment = new KeyspaceSettings(Address.class, "o_O"); assignment.setTimeToLive(5L); this.converter.getMappingContext().getMappingConfiguration().getKeyspaceConfiguration() .addKeyspaceSettings(assignment); Address address = new Address(); address.city = "Tear"; assertThat(write(address).getTimeToLive(), is(5L)); } @Test // DATAREDIS-425, DATAREDIS-634 public void writeShouldHonorCustomConversionOnRootType() { RedisCustomConversions customConversions = new RedisCustomConversions( Collections.singletonList(new AddressToBytesConverter())); RedisMappingContext mappingContext = new RedisMappingContext(); mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder()); this.converter = new MappingRedisConverter(mappingContext, null, resolverMock); this.converter.setCustomConversions(customConversions); this.converter.afterPropertiesSet(); Address address = new Address(); address.country = "Tel'aran'rhiod"; address.city = "unknown"; assertThat(write(address).getBucket(), isBucket().containingUtf8String("_raw", "{\"city\":\"unknown\",\"country\":\"Tel'aran'rhiod\"}")); } @Test // DATAREDIS-425, DATAREDIS-634 public void writeShouldHonorCustomConversionOnNestedType() { RedisCustomConversions customConversions = new RedisCustomConversions( Collections.singletonList(new AddressToBytesConverter())); RedisMappingContext mappingContext = new RedisMappingContext(); mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder()); this.converter = new MappingRedisConverter(mappingContext, null, resolverMock); this.converter.setCustomConversions(customConversions); this.converter.afterPropertiesSet(); Address address = new Address(); address.country = "Tel'aran'rhiod"; address.city = "unknown"; rand.address = address; assertThat(write(rand).getBucket(), isBucket().containingUtf8String("address", "{\"city\":\"unknown\",\"country\":\"Tel'aran'rhiod\"}")); } @Test // DATAREDIS-425 public void writeShouldHonorIndexOnCustomConversionForNestedType() { this.converter = new MappingRedisConverter(null, null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new AddressToBytesConverter()))); this.converter.afterPropertiesSet(); Address address = new Address(); address.country = "andor"; rand.address = address; assertThat(write(rand).getIndexedData(), hasItem(new SimpleIndexedPropertyValue(KEYSPACE_PERSON, "address.country", "andor"))); } @Test // DATAREDIS-425 public void writeShouldHonorIndexAnnotationsOnWhenCustomConversionOnNestedype() { this.converter = new MappingRedisConverter(new RedisMappingContext(), null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new AddressToBytesConverter()))); this.converter.afterPropertiesSet(); Address address = new Address(); address.country = "Tel'aran'rhiod"; address.city = "unknown"; rand.address = address; assertThat(write(rand).getIndexedData().isEmpty(), is(false)); } @Test // DATAREDIS-425 public void readShouldHonorCustomConversionOnRootType() { this.converter = new MappingRedisConverter(null, null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new BytesToAddressConverter()))); this.converter.afterPropertiesSet(); Map<String, String> map = new LinkedHashMap<String, String>(); map.put("_raw", "{\"city\":\"unknown\",\"country\":\"Tel'aran'rhiod\"}"); Address target = converter.read(Address.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target.city, is("unknown")); assertThat(target.country, is("Tel'aran'rhiod")); } @Test // DATAREDIS-425 public void readShouldHonorCustomConversionOnNestedType() { this.converter = new MappingRedisConverter(new RedisMappingContext(), null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new BytesToAddressConverter()))); this.converter.afterPropertiesSet(); Map<String, String> map = new LinkedHashMap<String, String>(); map.put("address", "{\"city\":\"unknown\",\"country\":\"Tel'aran'rhiod\"}"); Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target.address, notNullValue()); assertThat(target.address.city, is("unknown")); assertThat(target.address.country, is("Tel'aran'rhiod")); } @Test // DATAREDIS-425 public void writeShouldPickUpTimeToLiveFromPropertyIfPresent() { ExipringPersonWithExplicitProperty aviendha = new ExipringPersonWithExplicitProperty(); aviendha.id = "aviendha"; aviendha.ttl = 2L; assertThat(write(aviendha).getTimeToLive(), is(120L)); } @Test // DATAREDIS-425 public void writeShouldUseDefaultTimeToLiveIfPropertyIsPresentButNull() { ExipringPersonWithExplicitProperty aviendha = new ExipringPersonWithExplicitProperty(); aviendha.id = "aviendha"; assertThat(write(aviendha).getTimeToLive(), is(5L)); } @Test // DATAREDIS-425 public void writeShouldConsiderMapConvertersForRootType() { this.converter = new MappingRedisConverter(new RedisMappingContext(), null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new SpeciesToMapConverter()))); this.converter.afterPropertiesSet(); Species myrddraal = new Species(); myrddraal.name = "myrddraal"; myrddraal.alsoKnownAs = Arrays.asList("halfmen", "fades", "neverborn"); assertThat(write(myrddraal).getBucket(), isBucket().containingUtf8String("species-name", "myrddraal") .containingUtf8String("species-nicknames", "halfmen,fades,neverborn")); } @Test // DATAREDIS-425 public void writeShouldConsiderMapConvertersForNestedType() { this.converter = new MappingRedisConverter(null, null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new SpeciesToMapConverter()))); this.converter.afterPropertiesSet(); rand.species = new Species(); rand.species.name = "human"; assertThat(write(rand).getBucket(), isBucket().containingUtf8String("species.species-name", "human")); } @Test // DATAREDIS-425 public void readShouldConsiderMapConvertersForRootType() { this.converter = new MappingRedisConverter(new RedisMappingContext(), null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new MapToSpeciesConverter()))); this.converter.afterPropertiesSet(); Map<String, String> map = new LinkedHashMap<String, String>(); map.put("species-name", "trolloc"); Species target = converter.read(Species.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target, notNullValue()); assertThat(target.name, is("trolloc")); } @Test // DATAREDIS-425 public void readShouldConsiderMapConvertersForNestedType() { this.converter = new MappingRedisConverter(null, null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new MapToSpeciesConverter()))); this.converter.afterPropertiesSet(); Map<String, String> map = new LinkedHashMap<String, String>(); map.put("species.species-name", "trolloc"); Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target, notNullValue()); assertThat(target.species.name, is("trolloc")); } @Test // DATAREDIS-425 public void writeShouldConsiderMapConvertersInsideLists() { this.converter = new MappingRedisConverter(new RedisMappingContext(), null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new SpeciesToMapConverter()))); this.converter.afterPropertiesSet(); TheWheelOfTime twot = new TheWheelOfTime(); twot.species = new ArrayList<Species>(); Species myrddraal = new Species(); myrddraal.name = "myrddraal"; myrddraal.alsoKnownAs = Arrays.asList("halfmen", "fades", "neverborn"); twot.species.add(myrddraal); assertThat(write(twot).getBucket(), isBucket().containingUtf8String("species.[0].species-name", "myrddraal") .containingUtf8String("species.[0].species-nicknames", "halfmen,fades,neverborn")); } @Test // DATAREDIS-425 public void readShouldConsiderMapConvertersForValuesInList() { this.converter = new MappingRedisConverter(null, null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new MapToSpeciesConverter()))); this.converter.afterPropertiesSet(); Map<String, String> map = new LinkedHashMap<String, String>(); map.put("species.[0].species-name", "trolloc"); TheWheelOfTime target = converter.read(TheWheelOfTime.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target, notNullValue()); assertThat(target.species, notNullValue()); assertThat(target.species.get(0), notNullValue()); assertThat(target.species.get(0).name, is("trolloc")); } @Test // DATAREDIS-492 public void writeHandlesArraysProperly() { this.converter = new MappingRedisConverter(null, null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new ListToByteConverter()))); this.converter.afterPropertiesSet(); Map<String, Object> innerMap = new LinkedHashMap<String, Object>(); innerMap.put("address", "tyrionl@netflix.com"); innerMap.put("when", new String[] { "pipeline.failed" }); Map<String, Object> map = new LinkedHashMap<String, Object>(); map.put("email", Collections.singletonList(innerMap)); RedisData target = write(map); } @Test // DATAREDIS-492 public void writeHandlesArraysOfSimpleTypeProperly() { WithArrays source = new WithArrays(); source.arrayOfSimpleTypes = new String[] { "rand", "mat", "perrin" }; assertThat(write(source).getBucket(), isBucket().containingUtf8String("arrayOfSimpleTypes.[0]", "rand") .containingUtf8String("arrayOfSimpleTypes.[1]", "mat") .containingUtf8String("arrayOfSimpleTypes.[2]", "perrin")); } @Test // DATAREDIS-492 public void readHandlesArraysOfSimpleTypeProperly() { Map<String, String> source = new LinkedHashMap<String, String>(); source.put("arrayOfSimpleTypes.[0]", "rand"); source.put("arrayOfSimpleTypes.[1]", "mat"); source.put("arrayOfSimpleTypes.[2]", "perrin"); WithArrays target = read(WithArrays.class, source); assertThat(target.arrayOfSimpleTypes, IsEqual.equalTo(new String[] { "rand", "mat", "perrin" })); } @Test // DATAREDIS-492 public void writeHandlesArraysOfComplexTypeProperly() { WithArrays source = new WithArrays(); Species trolloc = new Species(); trolloc.name = "trolloc"; Species myrddraal = new Species(); myrddraal.name = "myrddraal"; myrddraal.alsoKnownAs = Arrays.asList("halfmen", "fades", "neverborn"); source.arrayOfCompexTypes = new Species[] { trolloc, myrddraal }; assertThat(write(source).getBucket(), isBucket().containingUtf8String("arrayOfCompexTypes.[0].name", "trolloc") // .containingUtf8String("arrayOfCompexTypes.[1].name", "myrddraal") // .containingUtf8String("arrayOfCompexTypes.[1].alsoKnownAs.[0]", "halfmen") // .containingUtf8String("arrayOfCompexTypes.[1].alsoKnownAs.[1]", "fades") // .containingUtf8String("arrayOfCompexTypes.[1].alsoKnownAs.[2]", "neverborn")); } @Test // DATAREDIS-492 public void readHandlesArraysOfComplexTypeProperly() { Map<String, String> source = new LinkedHashMap<String, String>(); source.put("arrayOfCompexTypes.[0].name", "trolloc"); source.put("arrayOfCompexTypes.[1].name", "myrddraal"); source.put("arrayOfCompexTypes.[1].alsoKnownAs.[0]", "halfmen"); source.put("arrayOfCompexTypes.[1].alsoKnownAs.[1]", "fades"); source.put("arrayOfCompexTypes.[1].alsoKnownAs.[2]", "neverborn"); WithArrays target = read(WithArrays.class, source); assertThat(target.arrayOfCompexTypes[0], notNullValue()); assertThat(target.arrayOfCompexTypes[0].name, is("trolloc")); assertThat(target.arrayOfCompexTypes[1], notNullValue()); assertThat(target.arrayOfCompexTypes[1].name, is("myrddraal")); assertThat(target.arrayOfCompexTypes[1].alsoKnownAs, contains("halfmen", "fades", "neverborn")); } @Test // DATAREDIS-489 public void writeHandlesArraysOfObjectTypeProperly() { Species trolloc = new Species(); trolloc.name = "trolloc"; WithArrays source = new WithArrays(); source.arrayOfObject = new Object[] { "rand", trolloc, 100L }; assertThat(write(source).getBucket(), isBucket().containingUtf8String("arrayOfObject.[0]", "rand") // .containingUtf8String("arrayOfObject.[0]._class", "java.lang.String") .containingUtf8String("arrayOfObject.[1]._class", Species.class.getName()) // .containingUtf8String("arrayOfObject.[1].name", "trolloc") // .containingUtf8String("arrayOfObject.[2]._class", "java.lang.Long") // .containingUtf8String("arrayOfObject.[2]", "100")); } @Test // DATAREDIS-489 public void readHandlesArraysOfObjectTypeProperly() { Map<String, String> source = new LinkedHashMap<String, String>(); source.put("arrayOfObject.[0]", "rand"); source.put("arrayOfObject.[0]._class", "java.lang.String"); source.put("arrayOfObject.[1]._class", Species.class.getName()); source.put("arrayOfObject.[1].name", "trolloc"); source.put("arrayOfObject.[2]._class", "java.lang.Long"); source.put("arrayOfObject.[2]", "100"); WithArrays target = read(WithArrays.class, source); assertThat(target.arrayOfObject[0], notNullValue()); assertThat(target.arrayOfObject[0], instanceOf(String.class)); assertThat(target.arrayOfObject[1], notNullValue()); assertThat(target.arrayOfObject[1], instanceOf(Species.class)); assertThat(target.arrayOfObject[2], notNullValue()); assertThat(target.arrayOfObject[2], instanceOf(Long.class)); } @Test // DATAREDIS-489 public void writeShouldAppendTyeHintToObjectPropertyValueTypesCorrectly() { TypeWithObjectValueTypes sample = new TypeWithObjectValueTypes(); sample.object = "bar"; Bucket bucket = write(sample).getBucket(); assertThat(bucket, isBucket().containingUtf8String("object", "bar").containingUtf8String("object._class", "java.lang.String")); } @Test // DATAREDIS-489 public void shouldWriteReadObjectPropertyValueTypeCorrectly() { TypeWithObjectValueTypes di = new TypeWithObjectValueTypes(); di.object = "foo"; RedisData rd = write(di); System.out.println(rd.getBucket().toString()); TypeWithObjectValueTypes result = converter.read(TypeWithObjectValueTypes.class, rd); assertThat(result.object, instanceOf(String.class)); } @Test // DATAREDIS-489 public void writeShouldAppendTyeHintToObjectMapValueTypesCorrectly() { TypeWithObjectValueTypes sample = new TypeWithObjectValueTypes(); sample.map.put("string", "bar"); sample.map.put("long", new Long(1L)); sample.map.put("date", new Date()); Bucket bucket = write(sample).getBucket(); assertThat(bucket, isBucket().containingUtf8String("map.[string]", "bar") .containingUtf8String("map.[string]._class", "java.lang.String")); assertThat(bucket, isBucket().containingUtf8String("map.[long]", "1").containingUtf8String("map.[long]._class", "java.lang.Long")); assertThat(bucket, isBucket().containingUtf8String("map.[date]._class", "java.util.Date")); } @Test // DATAREDIS-489 public void shouldWriteReadObjectMapValueTypeCorrectly() { TypeWithObjectValueTypes sample = new TypeWithObjectValueTypes(); sample.map.put("string", "bar"); sample.map.put("long", new Long(1L)); sample.map.put("date", new Date()); RedisData rd = write(sample); TypeWithObjectValueTypes result = converter.read(TypeWithObjectValueTypes.class, rd); assertThat(result.map.get("string"), instanceOf(String.class)); assertThat(result.map.get("long"), instanceOf(Long.class)); assertThat(result.map.get("date"), instanceOf(Date.class)); } @Test // DATAREDIS-489 public void writeShouldAppendTyeHintToObjectListValueTypesCorrectly() { TypeWithObjectValueTypes sample = new TypeWithObjectValueTypes(); sample.list.add("string"); sample.list.add(new Long(1L)); sample.list.add(new Date()); Bucket bucket = write(sample).getBucket(); assertThat(bucket, isBucket().containingUtf8String("list.[0]", "string").containingUtf8String("list.[0]._class", "java.lang.String")); assertThat(bucket, isBucket().containingUtf8String("list.[1]", "1").containingUtf8String("list.[1]._class", "java.lang.Long")); assertThat(bucket, isBucket().containingUtf8String("list.[2]._class", "java.util.Date")); } @Test // DATAREDIS-489 public void shouldWriteReadObjectListValueTypeCorrectly() { TypeWithObjectValueTypes sample = new TypeWithObjectValueTypes(); sample.list.add("string"); sample.list.add(new Long(1L)); sample.list.add(new Date()); RedisData rd = write(sample); TypeWithObjectValueTypes result = converter.read(TypeWithObjectValueTypes.class, rd); assertThat(result.list.get(0), instanceOf(String.class)); assertThat(result.list.get(1), instanceOf(Long.class)); assertThat(result.list.get(2), instanceOf(Date.class)); } @Test // DATAREDIS-509 public void writeHandlesArraysOfPrimitivesProperly() { Map<String, String> source = new LinkedHashMap<String, String>(); source.put("arrayOfPrimitives.[0]", "1"); source.put("arrayOfPrimitives.[1]", "2"); source.put("arrayOfPrimitives.[2]", "3"); WithArrays target = read(WithArrays.class, source); assertThat(target.arrayOfPrimitives[0], is(1)); assertThat(target.arrayOfPrimitives[1], is(2)); assertThat(target.arrayOfPrimitives[2], is(3)); } @Test // DATAREDIS-509 public void readHandlesArraysOfPrimitivesProperly() { WithArrays source = new WithArrays(); source.arrayOfPrimitives = new int[] { 1, 2, 3 }; assertThat(write(source).getBucket(), isBucket().containingUtf8String("arrayOfPrimitives.[0]", "1") .containingUtf8String("arrayOfPrimitives.[1]", "2").containingUtf8String("arrayOfPrimitives.[2]", "3")); } @Test // DATAREDIS-471 public void writeShouldNotAppendClassTypeHint() { Person value = new Person(); value.firstname = "rand"; value.age = 24; PartialUpdate<Person> update = new PartialUpdate<Person>("123", value); assertThat(write(update).getBucket().get("_class"), is(nullValue())); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdateSimpleValueCorrectly() { Person value = new Person(); value.firstname = "rand"; value.age = 24; PartialUpdate<Person> update = new PartialUpdate<Person>("123", value); assertThat(write(update).getBucket(), isBucket().containingUtf8String("firstname", "rand").containingUtf8String("age", "24")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithSimpleValueCorrectly() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("firstname", "rand").set("age", 24); assertThat(write(update).getBucket(), isBucket().containingUtf8String("firstname", "rand").containingUtf8String("age", "24")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdateNestedPathWithSimpleValueCorrectly() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("address.city", "two rivers"); assertThat(write(update).getBucket(), isBucket().containingUtf8String("address.city", "two rivers")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithComplexValueCorrectly() { Address address = new Address(); address.city = "two rivers"; address.country = "andor"; PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("address", address); assertThat(write(update).getBucket(), isBucket().containingUtf8String("address.city", "two rivers").containingUtf8String("address.country", "andor")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithSimpleListValueCorrectly() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("nicknames", Arrays.asList("dragon", "lews")); assertThat(write(update).getBucket(), isBucket().containingUtf8String("nicknames.[0]", "dragon").containingUtf8String("nicknames.[1]", "lews")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithComplexListValueCorrectly() { Person mat = new Person(); mat.firstname = "mat"; mat.age = 24; Person perrin = new Person(); perrin.firstname = "perrin"; PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("coworkers", Arrays.asList(mat, perrin)); assertThat(write(update).getBucket(), isBucket().containingUtf8String("coworkers.[0].firstname", "mat") .containingUtf8String("coworkers.[0].age", "24").containingUtf8String("coworkers.[1].firstname", "perrin")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithSimpleListValueWhenNotPassedInAsCollectionCorrectly() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("nicknames", "dragon"); assertThat(write(update).getBucket(), isBucket().containingUtf8String("nicknames.[0]", "dragon")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithComplexListValueWhenNotPassedInAsCollectionCorrectly() { Person mat = new Person(); mat.firstname = "mat"; mat.age = 24; PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("coworkers", mat); assertThat(write(update).getBucket(), isBucket().containingUtf8String("coworkers.[0].firstname", "mat") .containingUtf8String("coworkers.[0].age", "24")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithSimpleListValueWhenNotPassedInAsCollectionWithPositionalParameterCorrectly() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("nicknames.[5]", "dragon"); assertThat(write(update).getBucket(), isBucket().containingUtf8String("nicknames.[5]", "dragon")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithComplexListValueWhenNotPassedInAsCollectionWithPositionalParameterCorrectly() { Person mat = new Person(); mat.firstname = "mat"; mat.age = 24; PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("coworkers.[5]", mat); assertThat(write(update).getBucket(), isBucket().containingUtf8String("coworkers.[5].firstname", "mat") .containingUtf8String("coworkers.[5].age", "24")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithSimpleMapValueCorrectly() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("physicalAttributes", Collections.singletonMap("eye-color", "grey")); assertThat(write(update).getBucket(), isBucket().containingUtf8String("physicalAttributes.[eye-color]", "grey")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithComplexMapValueCorrectly() { Person tam = new Person(); tam.firstname = "tam"; tam.alive = false; PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("relatives", Collections.singletonMap("father", tam)); assertThat(write(update).getBucket(), isBucket().containingUtf8String("relatives.[father].firstname", "tam") .containingUtf8String("relatives.[father].alive", "0")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithSimpleMapValueWhenNotPassedInAsCollectionCorrectly() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("physicalAttributes", Collections.singletonMap("eye-color", "grey").entrySet().iterator().next()); assertThat(write(update).getBucket(), isBucket().containingUtf8String("physicalAttributes.[eye-color]", "grey")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithComplexMapValueWhenNotPassedInAsCollectionCorrectly() { Person tam = new Person(); tam.firstname = "tam"; tam.alive = false; PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("relatives", Collections.singletonMap("father", tam).entrySet().iterator().next()); assertThat(write(update).getBucket(), isBucket().containingUtf8String("relatives.[father].firstname", "tam") .containingUtf8String("relatives.[father].alive", "0")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithSimpleMapValueWhenNotPassedInAsCollectionWithPositionalParameterCorrectly() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("physicalAttributes.[eye-color]", "grey"); assertThat(write(update).getBucket(), isBucket().containingUtf8String("physicalAttributes.[eye-color]", "grey")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithSimpleMapValueOnNestedElementCorrectly() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("relatives.[father].firstname", "tam"); assertThat(write(update).getBucket(), isBucket().containingUtf8String("relatives.[father].firstname", "tam")); } @Test(expected = MappingException.class) // DATAREDIS-471 public void writeShouldThrowExceptionOnPartialUpdatePathWithSimpleMapValueWhenItsASingleValueWithoutPath() { PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("physicalAttributes", "grey"); write(update); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithRegisteredCustomConversionCorrectly() { this.converter = new MappingRedisConverter(null, null, resolverMock); this.converter .setCustomConversions(new RedisCustomConversions(Collections.singletonList(new AddressToBytesConverter()))); this.converter.afterPropertiesSet(); Address address = new Address(); address.country = "Tel'aran'rhiod"; address.city = "unknown"; PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("address", address); assertThat(write(update).getBucket(), isBucket().containingUtf8String("address", "{\"city\":\"unknown\",\"country\":\"Tel'aran'rhiod\"}")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithReferenceCorrectly() { Location tar = new Location(); tar.id = "1"; tar.name = "tar valon"; Location tear = new Location(); tear.id = "2"; tear.name = "city of tear"; PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class).set("visited", Arrays.asList(tar, tear)); assertThat(write(update).getBucket(), isBucket().containingUtf8String("visited.[0]", "locations:1").containingUtf8String("visited.[1]", "locations:2") // .without("visited.id") // .without("visited.name")); } @Test // DATAREDIS-471 public void writeShouldWritePartialUpdatePathWithListOfReferencesCorrectly() { Location location = new Location(); location.id = "1"; location.name = "tar valon"; PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class) // .set("location", location); assertThat(write(update).getBucket(), isBucket().containingUtf8String("location", "locations:1") // .without("location.id") // .without("location.name")); } @Test // DATAREDIS-471 public void writeShouldThrowExceptionForUpdateValueNotAssignableToDomainTypeProperty() { exception.expect(MappingException.class); exception.expectMessage("java.lang.String cannot be assigned"); exception.expectMessage("java.lang.Integer"); exception.expectMessage("age"); PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class) // .set("age", "twenty-four"); assertThat(write(update).getBucket().get("_class"), is(nullValue())); } @Test // DATAREDIS-471 public void writeShouldThrowExceptionForUpdateCollectionValueNotAssignableToDomainTypeProperty() { exception.expect(MappingException.class); exception.expectMessage("java.lang.String cannot be assigned"); exception.expectMessage(Person.class.getName()); exception.expectMessage("coworkers.[0]"); PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class) // .set("coworkers.[0]", "buh buh the bear"); assertThat(write(update).getBucket().get("_class"), is(nullValue())); } @Test // DATAREDIS-471 public void writeShouldThrowExceptionForUpdateValueInCollectionNotAssignableToDomainTypeProperty() { exception.expect(MappingException.class); exception.expectMessage("java.lang.String cannot be assigned"); exception.expectMessage(Person.class.getName()); exception.expectMessage("coworkers"); PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class) // .set("coworkers", Collections.singletonList("foo")); assertThat(write(update).getBucket().get("_class"), is(nullValue())); } @Test // DATAREDIS-471 public void writeShouldThrowExceptionForUpdateMapValueNotAssignableToDomainTypeProperty() { exception.expect(MappingException.class); exception.expectMessage("java.lang.String cannot be assigned"); exception.expectMessage(Person.class.getName()); exception.expectMessage("relatives.[father]"); PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class) // .set("relatives.[father]", "buh buh the bear"); assertThat(write(update).getBucket().get("_class"), is(nullValue())); } @Test // DATAREDIS-471 public void writeShouldThrowExceptionForUpdateValueInMapNotAssignableToDomainTypeProperty() { exception.expect(MappingException.class); exception.expectMessage("java.lang.String cannot be assigned"); exception.expectMessage(Person.class.getName()); exception.expectMessage("relatives.[father]"); PartialUpdate<Person> update = new PartialUpdate<Person>("123", Person.class) // .set("relatives", Collections.singletonMap("father", "buh buh the bear")); assertThat(write(update).getBucket().get("_class"), is(nullValue())); } private RedisData write(Object source) { RedisData rdo = new RedisData(); converter.write(source, rdo); return rdo; } private <T> T read(Class<T> type, Map<String, String> source) { return converter.read(type, new RedisData(Bucket.newBucketFromStringMap(source))); } @WritingConverter static class AddressToBytesConverter implements Converter<Address, byte[]> { private final ObjectMapper mapper; private final Jackson2JsonRedisSerializer<Address> serializer; AddressToBytesConverter() { mapper = new ObjectMapper(); mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker() .withFieldVisibility(Visibility.ANY).withGetterVisibility(Visibility.NONE) .withSetterVisibility(Visibility.NONE).withCreatorVisibility(Visibility.NONE)); serializer = new Jackson2JsonRedisSerializer<Address>(Address.class); serializer.setObjectMapper(mapper); } @Override public byte[] convert(Address value) { return serializer.serialize(value); } } @WritingConverter static class SpeciesToMapConverter implements Converter<Species, Map<String, byte[]>> { @Override public Map<String, byte[]> convert(Species source) { if (source == null) { return null; } Map<String, byte[]> map = new LinkedHashMap<String, byte[]>(); if (source.name != null) { map.put("species-name", source.name.getBytes(Charset.forName("UTF-8"))); } map.put("species-nicknames", StringUtils.collectionToCommaDelimitedString(source.alsoKnownAs).getBytes(Charset.forName("UTF-8"))); return map; } } @WritingConverter static class ListToByteConverter implements Converter<List, byte[]> { private final ObjectMapper mapper; private final Jackson2JsonRedisSerializer<List> serializer; ListToByteConverter() { mapper = new ObjectMapper(); mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker() .withFieldVisibility(Visibility.ANY).withGetterVisibility(Visibility.NONE) .withSetterVisibility(Visibility.NONE).withCreatorVisibility(Visibility.NONE)); serializer = new Jackson2JsonRedisSerializer<List>(List.class); serializer.setObjectMapper(mapper); } @Override public byte[] convert(List source) { if (source == null || source.isEmpty()) { return null; } return serializer.serialize(source); } } @ReadingConverter static class MapToSpeciesConverter implements Converter<Map<String, byte[]>, Species> { @Override public Species convert(Map<String, byte[]> source) { if (source == null || source.isEmpty()) { return null; } Species species = new Species(); if (source.containsKey("species-name")) { species.name = new String(source.get("species-name"), Charset.forName("UTF-8")); } if (source.containsKey("species-nicknames")) { species.alsoKnownAs = Arrays.asList(StringUtils .commaDelimitedListToStringArray(new String(source.get("species-nicknames"), Charset.forName("UTF-8")))); } return species; } } @ReadingConverter static class BytesToAddressConverter implements Converter<byte[], Address> { private final ObjectMapper mapper; private final Jackson2JsonRedisSerializer<Address> serializer; BytesToAddressConverter() { mapper = new ObjectMapper(); mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker() .withFieldVisibility(Visibility.ANY).withGetterVisibility(Visibility.NONE) .withSetterVisibility(Visibility.NONE).withCreatorVisibility(Visibility.NONE)); serializer = new Jackson2JsonRedisSerializer<Address>(Address.class); serializer.setObjectMapper(mapper); } @Override public Address convert(byte[] value) { return serializer.deserialize(value); } } }