diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java index 6456f3b6f..e3c048d1f 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java @@ -49,7 +49,6 @@ import org.springframework.data.mapping.model.ConvertingPropertyAccessor; import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider; -import org.springframework.data.mapping.model.PropertyValueProvider; import org.springframework.data.mapping.model.SpELContext; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; @@ -189,8 +188,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter CassandraUDTValueProvider valueProvider = new CassandraUDTValueProvider(udtValue, CodecRegistry.DEFAULT_INSTANCE, expressionEvaluator); - PersistentEntityParameterValueProvider parameterValueProvider = new PersistentEntityParameterValueProvider<>( - entity, new MappingAndConvertingValueProvider(valueProvider), Optional.empty()); + PersistentEntityParameterValueProvider parameterValueProvider = getParameterValueProvider( + entity, valueProvider); EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity); S instance = instantiator.createInstance(entity, parameterValueProvider); @@ -200,6 +199,12 @@ public class MappingCassandraConverter extends AbstractCassandraConverter return instance; } + private PersistentEntityParameterValueProvider getParameterValueProvider( + CassandraPersistentEntity entity, CassandraValueProvider valueProvider) { + return new PersistentEntityParameterValueProvider<>(entity, new MappingAndConvertingValueProvider(valueProvider), + Optional.empty()); + } + protected void readPropertiesFromRow(CassandraPersistentEntity entity, CassandraRowValueProvider row, PersistentPropertyAccessor propertyAccessor) { @@ -248,10 +253,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter @SuppressWarnings("unused") protected Object instantiatePrimaryKey(CassandraPersistentEntity entity, CassandraPersistentProperty keyProperty, - PropertyValueProvider propertyProvider) { + CassandraValueProvider propertyProvider) { return instantiators.getInstantiatorFor(entity).createInstance(entity, - new PersistentEntityParameterValueProvider<>(entity, propertyProvider, Optional.empty())); + getParameterValueProvider(entity, propertyProvider)); } /* (non-Javadoc) @@ -843,8 +848,13 @@ public class MappingCassandraConverter extends AbstractCassandraConverter * @return the return value, may be {@literal null}. */ @SuppressWarnings("unchecked") - private Optional getReadValue(PropertyValueProvider row, - CassandraPersistentProperty property) { + protected Optional getReadValue(CassandraValueProvider row, CassandraPersistentProperty property) { + + if (property.isCompositePrimaryKey()) { + + CassandraPersistentEntity keyEntity = mappingContext.getRequiredPersistentEntity(property); + return Optional.of((T) instantiatePrimaryKey(keyEntity, property, row)); + } Optional obj = row.getPropertyValue(property); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/RowMockUtil.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/RowMockUtil.java index c72bae05a..6197423f1 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/RowMockUtil.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/RowMockUtil.java @@ -70,6 +70,13 @@ public class RowMockUtil { .thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].type); when(rowMock.getObject(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value); + when(rowMock.getString(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value); + when(rowMock.getDate(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value); + when(rowMock.getBool(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value); + when(rowMock.getInet(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value); + when(rowMock.getTimestamp(anyInt())) + .thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value); + when(rowMock.getUUID(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value); return rowMock; } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUnitTests.java index 812605d3d..867bd6a75 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUnitTests.java @@ -17,11 +17,12 @@ package org.springframework.data.cassandra.core.convert; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; -import static org.mockito.Mockito.*; import static org.springframework.data.cassandra.RowMockUtil.*; import static org.springframework.data.cassandra.repository.support.BasicMapId.*; import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.Value; import java.io.Serializable; import java.math.BigDecimal; @@ -46,9 +47,6 @@ 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.SpringVersion; import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.data.cassandra.RowMockUtil; @@ -88,15 +86,13 @@ import com.datastax.driver.core.querybuilder.Update.Assignments; * @author Mark Paluch * @soundtrack Outlandich - Dont Leave Me Feat Cyt (Sun Kidz Electrocore Mix) */ -@SuppressWarnings("Since15") -@RunWith(MockitoJUnitRunner.class) public class MappingCassandraConverterUnitTests { private static final Version VERSION_4_3 = Version.parse("4.3"); @Rule public final ExpectedException expectedException = ExpectedException.none(); - @Mock Row rowMock; + Row rowMock; CassandraMappingContext mappingContext; MappingCassandraConverter mappingCassandraConverter; @@ -257,7 +253,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-280 public void shouldReadStringCorrectly() { - when(rowMock.getString(0)).thenReturn("foo"); + rowMock = RowMockUtil.newRowMock(column("foo", "foo", DataType.varchar())); String result = mappingCassandraConverter.readRow(String.class, rowMock); @@ -267,7 +263,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-280 public void shouldReadIntegerCorrectly() { - when(rowMock.getObject(0)).thenReturn(2); + rowMock = RowMockUtil.newRowMock(column("foo", 2, DataType.varint())); Integer result = mappingCassandraConverter.readRow(Integer.class, rowMock); @@ -277,7 +273,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-280 public void shouldReadLongCorrectly() { - when(rowMock.getObject(0)).thenReturn(2); + rowMock = RowMockUtil.newRowMock(column("foo", 2, DataType.varint())); Long result = mappingCassandraConverter.readRow(Long.class, rowMock); @@ -287,7 +283,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-280 public void shouldReadDoubleCorrectly() { - when(rowMock.getObject(0)).thenReturn(2D); + rowMock = RowMockUtil.newRowMock(column("foo", 2D, DataType.cdouble())); Double result = mappingCassandraConverter.readRow(Double.class, rowMock); @@ -297,7 +293,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-280 public void shouldReadFloatCorrectly() { - when(rowMock.getObject(0)).thenReturn(2F); + rowMock = RowMockUtil.newRowMock(column("foo", 2F, DataType.cdouble())); Float result = mappingCassandraConverter.readRow(Float.class, rowMock); @@ -307,7 +303,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-280 public void shouldReadBigIntegerCorrectly() { - when(rowMock.getObject(0)).thenReturn(BigInteger.valueOf(2)); + rowMock = RowMockUtil.newRowMock(column("foo", BigInteger.valueOf(2), DataType.bigint())); BigInteger result = mappingCassandraConverter.readRow(BigInteger.class, rowMock); @@ -317,7 +313,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-280 public void shouldReadBigDecimalCorrectly() { - when(rowMock.getObject(0)).thenReturn(BigDecimal.valueOf(2)); + rowMock = RowMockUtil.newRowMock(column("foo", BigDecimal.valueOf(2), DataType.decimal())); BigDecimal result = mappingCassandraConverter.readRow(BigDecimal.class, rowMock); @@ -329,7 +325,7 @@ public class MappingCassandraConverterUnitTests { UUID uuid = UUID.randomUUID(); - when(rowMock.getUUID(0)).thenReturn(uuid); + rowMock = RowMockUtil.newRowMock(column("foo", uuid, DataType.uuid())); UUID result = mappingCassandraConverter.readRow(UUID.class, rowMock); @@ -341,7 +337,7 @@ public class MappingCassandraConverterUnitTests { InetAddress localHost = InetAddress.getLocalHost(); - when(rowMock.getInet(0)).thenReturn(localHost); + rowMock = RowMockUtil.newRowMock(column("foo", localHost, DataType.inet())); InetAddress result = mappingCassandraConverter.readRow(InetAddress.class, rowMock); @@ -353,7 +349,7 @@ public class MappingCassandraConverterUnitTests { Date date = new Date(1); - when(rowMock.getTimestamp(0)).thenReturn(date); + rowMock = RowMockUtil.newRowMock(column("foo", date, DataType.timestamp())); Date result = mappingCassandraConverter.readRow(Date.class, rowMock); @@ -365,7 +361,7 @@ public class MappingCassandraConverterUnitTests { LocalDate date = LocalDate.fromDaysSinceEpoch(1234); - when(rowMock.getDate(0)).thenReturn(date); + rowMock = RowMockUtil.newRowMock(column("foo", date, DataType.date())); LocalDate result = mappingCassandraConverter.readRow(LocalDate.class, rowMock); @@ -375,7 +371,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-280 public void shouldReadBooleanCorrectly() { - when(rowMock.getBool(0)).thenReturn(true); + rowMock = RowMockUtil.newRowMock(column("foo", true, DataType.cboolean())); Boolean result = mappingCassandraConverter.readRow(Boolean.class, rowMock); @@ -388,7 +384,7 @@ public class MappingCassandraConverterUnitTests { LocalDateTime now = LocalDateTime.now(); Instant instant = now.toInstant(ZoneOffset.UTC); - Row rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), + rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), column("localdate", Date.from(instant), DataType.timestamp())); TypeWithLocalDate result = mappingCassandraConverter.readRow(TypeWithLocalDate.class, rowMock); @@ -471,7 +467,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-296 public void shouldReadLocalDateTimeUsingCassandraDateCorrectly() { - Row rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), + rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), column("localDate", LocalDate.fromYearMonthDay(2010, 7, 4), DataType.date())); TypeWithLocalDateMappedToDate result = mappingCassandraConverter.readRow(TypeWithLocalDateMappedToDate.class, @@ -515,7 +511,7 @@ public class MappingCassandraConverterUnitTests { LocalDateTime now = LocalDateTime.now(); Instant instant = now.toInstant(ZoneOffset.UTC); - Row rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), + rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), column("localDateTime", Date.from(instant), DataType.timestamp())); TypeWithLocalDate result = mappingCassandraConverter.readRow(TypeWithLocalDate.class, rowMock); @@ -531,7 +527,7 @@ public class MappingCassandraConverterUnitTests { LocalDateTime now = LocalDateTime.now(); Instant instant = now.toInstant(ZoneOffset.UTC); - Row rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), + rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), column("instant", Date.from(instant), DataType.timestamp())); TypeWithInstant result = mappingCassandraConverter.readRow(TypeWithInstant.class, rowMock); @@ -543,7 +539,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-296 public void shouldReadZoneIdCorrectly() { - Row rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), + rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), column("zoneId", "Europe/Paris", DataType.varchar())); TypeWithZoneId result = mappingCassandraConverter.readRow(TypeWithZoneId.class, rowMock); @@ -555,7 +551,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-296 public void shouldReadJodaLocalDateTimeUsingCassandraDateCorrectly() { - Row rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), + rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), column("localDate", LocalDate.fromYearMonthDay(2010, 7, 4), DataType.date())); TypeWithJodaLocalDateMappedToDate result = mappingCassandraConverter @@ -596,7 +592,7 @@ public class MappingCassandraConverterUnitTests { @Test // DATACASS-296 public void shouldReadThreeTenBpLocalDateTimeUsingCassandraDateCorrectly() { - Row rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), + rowMock = RowMockUtil.newRowMock(column("id", "my-id", DataType.ascii()), column("localDate", LocalDate.fromYearMonthDay(2010, 7, 4), DataType.date())); TypeWithThreeTenBpLocalDateMappedToDate result = mappingCassandraConverter @@ -821,6 +817,19 @@ public class MappingCassandraConverterUnitTests { assertThat(getWherePredicates(delete)).containsEntry("lastname", "White"); } + @Test // DATACASS-463 + public void shouldReadTypeWithCompositePrimaryKeyCorrectly() { + + // condition, localDate + Row row = RowMockUtil.newRowMock(column("condition", "MINT", DataType.varchar()), + column("localdate", LocalDate.fromYearMonthDay(2017, 1, 2), DataType.date())); + + TypeWithEnumAndLocalDateKey result = mappingCassandraConverter.read(TypeWithEnumAndLocalDateKey.class, row); + + assertThat(result.id.condition).isEqualTo(Condition.MINT); + assertThat(result.id.localDate).isEqualTo(java.time.LocalDate.of(2017, 1, 2)); + } + @Test // DATACASS-308 public void shouldWriteWhereConditionForTypeWithPkClassKeyUsingMapId() { @@ -980,6 +989,22 @@ public class MappingCassandraConverterUnitTests { } } + @PrimaryKeyClass + @RequiredArgsConstructor + @Value + public static class EnumAndDateCompositePrimaryKey implements Serializable { + + @PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.PARTITIONED) private final Condition condition; + + @PrimaryKeyColumn(ordinal = 2, type = PrimaryKeyType.PARTITIONED) private final java.time.LocalDate localDate; + } + + @RequiredArgsConstructor + public static class TypeWithEnumAndLocalDateKey { + + @PrimaryKey private final EnumAndDateCompositePrimaryKey id; + } + @Table public static class EnumPrimaryKey {