diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index a1a8f0206..6d10159cc 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -409,11 +409,10 @@ public class CassandraTemplate implements CassandraOperations { String.format("Entity class [%s] has no primary key", entityClass.getName()))); if (idProperty.isCompositePrimaryKey()) { - String typeName = idProperty.getCompositePrimaryKeyEntity().getType().getName(); throw new IllegalArgumentException( String.format("Entity class [%s] uses a composite primary key class [%s] which this method can't support", - entityClass.getName(), typeName)); + entityClass.getName(), idProperty.getType().getName())); } Select select = QueryBuilder.select().all().from(entity.getTableName().toCql()); 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 933d199db..5f8a41fb6 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 @@ -207,8 +207,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter if (property.isCompositePrimaryKey()) { - CassandraPersistentEntity keyEntity = property.getCompositePrimaryKeyEntity(); - + CassandraPersistentEntity keyEntity = mappingContext.getRequiredPersistentEntity(property); Optional optionalKey = propertyAccessor.getProperty(property); if (!optionalKey.isPresent()) { @@ -216,8 +215,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter } // now recurse on using the key this time - optionalKey.ifPresent(key -> readProperties(property.getCompositePrimaryKeyEntity(), valueProvider, - getConvertingAccessor(key, keyEntity))); + optionalKey.ifPresent(key -> readProperties(keyEntity, valueProvider, getConvertingAccessor(key, keyEntity))); // now that the key's properties have been populated, set the key property on the entity propertyAccessor.setProperty(property, optionalKey); @@ -338,12 +336,14 @@ public class MappingCassandraConverter extends AbstractCassandraConverter } if (property.isCompositePrimaryKey()) { + if (log.isDebugEnabled()) { log.debug("Property is a compositeKey"); } - writeMapFromWrapper(getConvertingAccessor(value.orElse(null), property.getCompositePrimaryKeyEntity()), insert, - property.getCompositePrimaryKeyEntity()); + CassandraPersistentEntity compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property); + writeMapFromWrapper(getConvertingAccessor(value.orElse(null), compositePrimaryKey), insert, + compositePrimaryKey); return; } @@ -368,12 +368,14 @@ public class MappingCassandraConverter extends AbstractCassandraConverter } if (property.isCompositePrimaryKey()) { + if (log.isDebugEnabled()) { log.debug("Property is a compositeKey"); } - writeInsertFromWrapper(getConvertingAccessor(value.orElse(null), property.getCompositePrimaryKeyEntity()), - insert, property.getCompositePrimaryKeyEntity()); + CassandraPersistentEntity compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property); + writeInsertFromWrapper(getConvertingAccessor(value.orElse(null), compositePrimaryKey), insert, + compositePrimaryKey); return; } @@ -402,8 +404,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter Optional value = getWriteValue(property, accessor); if (property.isCompositePrimaryKey()) { - CassandraPersistentEntity keyEntity = property.getCompositePrimaryKeyEntity(); - writeUpdateFromWrapper(getConvertingAccessor(value.orElse(null), keyEntity), update, keyEntity); + + CassandraPersistentEntity compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property); + + writeUpdateFromWrapper(getConvertingAccessor(value.orElse(null), compositePrimaryKey), update, + compositePrimaryKey); return; } @@ -447,6 +452,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter }); } + @SuppressWarnings("unchecked") private Collection getWhereClauses(Object source, CassandraPersistentEntity entity) { Assert.notNull(source, "Id source must not be null"); @@ -463,7 +469,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter // FIXME: Generics CassandraPersistentEntity whereEntity = optionalCompositeIdProperty // - .map(CassandraPersistentProperty::getCompositePrimaryKeyEntity) // + .map(it -> (CassandraPersistentEntity) mappingContext.getRequiredPersistentEntity(it)) // .orElse((CassandraPersistentEntity) entity); return getWhereClauses((MapId) id, whereEntity); @@ -480,8 +486,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter .orElseThrow(() -> new InvalidDataAccessApiUsageException( String.format("Cannot use [%s] as composite Id for [%s]", id, entity.getName()))); - return getWhereClauses(getConvertingAccessor(id, compositeIdProperty.getCompositePrimaryKeyEntity()), - compositeIdProperty.getCompositePrimaryKeyEntity()); + CassandraPersistentEntity compositePrimaryKey = mappingContext + .getRequiredPersistentEntity(compositeIdProperty); + return getWhereClauses(getConvertingAccessor(id, compositePrimaryKey), compositePrimaryKey); } Class targetType = getTargetType(idProperty); @@ -588,9 +595,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter protected Class transformClassToBeanClassLoaderClass(Class entity) { try { return (Class) ClassUtils.forName(entity.getName(), beanClassLoader); - } catch (ClassNotFoundException e) { - return entity; - } catch (LinkageError e) { + } catch (ClassNotFoundException | LinkageError e) { return entity; } } @@ -894,7 +899,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter Class rawComponentType = componentType.map(TypeInformation::getType).orElse((Class) List.class); collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class; - Collection items = targetType.getType().isArray() ? new ArrayList() + Collection items = targetType.getType().isArray() ? new ArrayList<>() : CollectionFactory.createCollection(collectionType, rawComponentType, sourceValue.size()); if (sourceValue.isEmpty()) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/QueryMapper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/QueryMapper.java index a4363c8d2..80ba87912 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/QueryMapper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/QueryMapper.java @@ -103,19 +103,6 @@ public class QueryMapper { return this.mappingContext; } - /** - * Return {@link ColumnSelector}s for all columns of {@link CassandraPersistentEntity}. - * - * @param entity must not be {@literal null}. - * @return {@link ColumnSelector}s for all columns of {@link CassandraPersistentEntity}. - */ - public List getColumns(CassandraPersistentEntity entity) { - - return entity.getPersistentProperties() // - .flatMap(p -> p.getColumnNames().stream()).map(ColumnSelector::from) // - .collect(Collectors.toList()); - } - /** * Map a {@link Filter} with a {@link CassandraPersistentEntity type hint}. Filter mapping translates property names * to column names and maps {@link Predicate} values to simple Cassandra values. @@ -137,6 +124,11 @@ public class QueryMapper { Predicate predicate = criteriaDefinition.getPredicate(); + field.getProperty().filter(CassandraPersistentProperty::isCompositePrimaryKey).ifPresent(it -> { + throw new IllegalArgumentException( + "Cannot use composite primary key directly. Reference a property of the composite primary key"); + }); + Optional value = Optional.ofNullable(predicate.getValue()); TypeInformation typeInformation = getTypeInformation(field, value); Optional mappedValue = getConverter().convertToColumnType(value, typeInformation); @@ -179,22 +171,26 @@ public class QueryMapper { } if (columns.isEmpty()) { - - entity.doWithProperties((PropertyHandler) property -> { - - if (property.isCompositePrimaryKey()) { - for (CqlIdentifier cqlIdentifier : property.getColumnNames()) { - selectors.add(ColumnSelector.from(cqlIdentifier.toCql())); - } - } else { - selectors.add(ColumnSelector.from(property.getColumnName().toCql())); - } - }); + addColumns(entity, selectors); } return selectors; } + private void addColumns(CassandraPersistentEntity entity, List selectors) { + + entity.doWithProperties((PropertyHandler) property -> { + + if (property.isCompositePrimaryKey()) { + + CassandraPersistentEntity primaryKeyEntity = mappingContext.getRequiredPersistentEntity(property); + addColumns(primaryKeyEntity, selectors); + } else { + selectors.add(ColumnSelector.from(property.getColumnName().toCql())); + } + }); + } + private Selector getMappedSelector(Selector selector, CqlIdentifier cqlIdentifier) { if (selector instanceof ColumnSelector) { @@ -311,7 +307,14 @@ public class QueryMapper { try { if (field.getProperty().isPresent()) { - return field.getProperty().map(CassandraPersistentProperty::getColumnName); + return field.getProperty().map(cassandraPersistentProperty -> { + + if (cassandraPersistentProperty.isCompositePrimaryKey()) { + throw new IllegalArgumentException( + "Cannot use composite primary key directly. Reference a property of the composite primary key"); + } + return cassandraPersistentProperty.getColumnName(); + }); } if (column.getColumnName().isPresent()) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java index ecd3a5e0a..5cddeb150 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java @@ -17,9 +17,7 @@ package org.springframework.data.cassandra.core.mapping; import static org.springframework.data.cql.core.CqlIdentifier.*; -import java.util.ArrayList; import java.util.Comparator; -import java.util.List; import java.util.Optional; import org.springframework.beans.BeansException; @@ -32,7 +30,6 @@ import org.springframework.data.cql.core.CqlIdentifier; import org.springframework.data.cql.support.exception.UnsupportedCassandraOperationException; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.AssociationHandler; -import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.BasicPersistentEntity; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.util.TypeInformation; @@ -60,8 +57,6 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity, CassandraPersistentProperty> mappingContext; - private ApplicationContext context; private StandardEvaluationContext spelContext; @@ -76,35 +71,21 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity typeInformation) { - this(typeInformation, null, DEFAULT_VERIFIER); + this(typeInformation, DEFAULT_VERIFIER); } /** * Create a new {@link BasicCassandraPersistentEntity} with the given {@link TypeInformation}. Will default the table * name to the entity's simple type name. * - * @param typeInformation + * @param typeInformation must not be {@literal null}. + * @param verifier must not be {@literal null}. */ public BasicCassandraPersistentEntity(TypeInformation typeInformation, - MappingContext, CassandraPersistentProperty> mappingContext) { - this(typeInformation, mappingContext, DEFAULT_VERIFIER); - } - - /** - * Create a new {@link BasicCassandraPersistentEntity} with the given {@link TypeInformation}. Will default the table - * name to the entity's simple type name. - * - * @param typeInformation - */ - public BasicCassandraPersistentEntity(TypeInformation typeInformation, - MappingContext, CassandraPersistentProperty> mappingContext, CassandraPersistentEntityMetadataVerifier verifier) { - // FIXME: Constructor with comparator, no optionality here super(typeInformation, PROPERTY_COMPARATOR); - this.mappingContext = mappingContext; - setVerifier(verifier); } @@ -141,41 +122,12 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity getCompositePrimaryKeyProperties() { - - List properties = new ArrayList<>(); - - Assert.state(isCompositePrimaryKey(), - String.format("[%s] does not represent a composite primary key class", this.getType().getName())); - - addCompositePrimaryKeyProperties(this, properties); - - return properties; - } - - protected void addCompositePrimaryKeyProperties(CassandraPersistentEntity compositePrimaryKeyEntity, - final List properties) { - - compositePrimaryKeyEntity.getPersistentProperties().forEach(property -> { - - if (property.isCompositePrimaryKey()) { - addCompositePrimaryKeyProperties(property.getCompositePrimaryKeyEntity(), properties); - } else { - properties.add(property); - } - - }); - } - /* (non-Javadoc) * @see org.springframework.data.mapping.model.BasicPersistentEntity#verify() */ @Override public void verify() throws MappingException { + super.verify(); if (verifier != null) { @@ -225,14 +177,6 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity, CassandraPersistentProperty> getMappingContext() { - return mappingContext; - } - /* (non-Javadoc) * @see org.springframework.data.cassandra.mapping.CassandraPersistentEntity#setTableName(org.springframework.cassandra.core.cql.CqlIdentifier) */ diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentProperty.java index 8ec656b40..a0e082364 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentProperty.java @@ -17,13 +17,10 @@ package org.springframework.data.cassandra.core.mapping; import static org.springframework.data.cql.core.CqlIdentifier.*; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -36,12 +33,10 @@ import org.springframework.data.cql.core.CqlIdentifier; import org.springframework.data.cql.core.Ordering; import org.springframework.data.cql.core.PrimaryKeyType; import org.springframework.data.mapping.Association; -import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.SimpleTypeHolder; -import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.util.Assert; @@ -71,12 +66,12 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP /** * Whether this property has been explicitly instructed to force quote column names. */ - private Boolean forceQuote; + private Optional forceQuote = Optional.empty(); /** * An unmodifiable list of this property's column names. */ - private List columnNames; + private CqlIdentifier columnName; /** * Create a new {@link BasicCassandraPersistentProperty}. @@ -133,40 +128,17 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return (CassandraPersistentEntity) super.getOwner(); } - /* (non-Javadoc) - * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#isCompositePrimaryKey() - */ - @Override - public boolean isCompositePrimaryKey() { - return (AnnotatedElementUtils.findMergedAnnotation(getType(), PrimaryKeyClass.class) != null); - } - - /** - * @return - */ - public Class getCompositePrimaryKeyType() { - return (isCompositePrimaryKey() ? getType() : null); - } - - /* (non-Javadoc) - * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#getCompositePrimaryKeyTypeInformation() - */ - @Override - public TypeInformation getCompositePrimaryKeyTypeInformation() { - return (isCompositePrimaryKey() ? ClassTypeInformation.from(getCompositePrimaryKeyType()) : null); - } - /* (non-Javadoc) * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#getColumnName() */ @Override public CqlIdentifier getColumnName() { - List columnNames = getColumnNames(); + if (this.columnName == null) { + this.columnName = determineColumnName(); + } - Assert.state(columnNames.size() == 1, String.format("Property [%s] has no single column mapping", getName())); - - return columnNames.get(0); + return this.columnName; } /* (non-Javadoc) @@ -177,9 +149,6 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return findAnnotation(PrimaryKeyColumn.class).map(PrimaryKeyColumn::ordering); } - /* (non-Javadoc) - * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#getDataType() - */ /* (non-Javadoc) * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#getDataType() */ @@ -206,6 +175,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } if (isMap()) { + List> args = getTypeInformation().getTypeArguments(); ensureTypeArguments(args.size(), 2); @@ -214,6 +184,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } if (isCollectionLike()) { + List> args = getTypeInformation().getTypeArguments(); ensureTypeArguments(args.size(), 1); @@ -285,13 +256,19 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } /* (non-Javadoc) - * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#isClusterKeyColumn() + * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#isCompositePrimaryKey() */ @Override - public boolean isClusterKeyColumn() { + public boolean isCompositePrimaryKey() { + return (AnnotatedElementUtils.findMergedAnnotation(getType(), PrimaryKeyClass.class) != null); + } - return findAnnotation(PrimaryKeyColumn.class) - .filter(primaryKeyColumn -> PrimaryKeyType.CLUSTERED.equals(primaryKeyColumn.type())).isPresent(); + /* (non-Javadoc) + * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#isPrimaryKeyColumn() + */ + @Override + public boolean isPrimaryKeyColumn() { + return isAnnotationPresent(PrimaryKeyColumn.class); } /* (non-Javadoc) @@ -305,11 +282,13 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } /* (non-Javadoc) - * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#isPrimaryKeyColumn() + * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#isClusterKeyColumn() */ @Override - public boolean isPrimaryKeyColumn() { - return isAnnotationPresent(PrimaryKeyColumn.class); + public boolean isClusterKeyColumn() { + + return findAnnotation(PrimaryKeyColumn.class) + .filter(primaryKeyColumn -> PrimaryKeyType.CLUSTERED.equals(primaryKeyColumn.type())).isPresent(); } protected DataType getDataTypeFor(DataType.Name dataTypeName) { @@ -327,16 +306,6 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP protected DataType getDataTypeFor(Class javaType) { - Optional> optionalEntity = getOwner().getMappingContext().getPersistentEntity(javaType) - .map(CassandraPersistentEntity.class::cast); - - Optional> udtEntity = optionalEntity - .filter(CassandraPersistentEntity::isUserDefinedType); - - if (udtEntity.isPresent()) { - return udtEntity.map(CassandraPersistentEntity::getUserType).get(); - } - DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(javaType); if (dataType == null) { @@ -356,52 +325,36 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } } - /* (non-Javadoc) - * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#getColumnNames() - */ - @Override - public List getColumnNames() { - - columnNames = (columnNames != null ? columnNames : Collections.unmodifiableList(determineColumnNames())); - - return columnNames; - } - - protected List determineColumnNames() { - - List columnNames = new ArrayList<>(); + private CqlIdentifier determineColumnName() { if (isCompositePrimaryKey()) { // then the id type has @PrimaryKeyClass - addCompositePrimaryKeyColumnNames(getCompositePrimaryKeyEntity(), columnNames); - } else { // else we're dealing with a single-column field - String defaultName = getName(); // TODO: replace with naming strategy class - String overriddenName; - boolean forceQuote; - - if (isIdProperty()) { // then the id is of a simple type (since it's not a composite primary key) - Optional optionalPrimaryKey = findAnnotation(PrimaryKey.class); - overriddenName = optionalPrimaryKey.map(PrimaryKey::value).orElse(""); - forceQuote = optionalPrimaryKey.map(PrimaryKey::forceQuote).orElse(false); - - } else if (isPrimaryKeyColumn()) { // then it's a simple type - Optional optionalPrimaryKey = findAnnotation(PrimaryKeyColumn.class); - overriddenName = optionalPrimaryKey.map(PrimaryKeyColumn::value).orElse(""); - forceQuote = optionalPrimaryKey.map(PrimaryKeyColumn::forceQuote).orElse(false); - - } else { // then it's a vanilla column with the assumption that it's mapped to a single column - Optional optionalColumn = findAnnotation(Column.class); - overriddenName = optionalColumn.map(Column::value).orElse(""); - forceQuote = optionalColumn.map(Column::forceQuote).orElse(false); - } - - columnNames.add(createColumnName(defaultName, overriddenName, forceQuote)); - + return null; } - return columnNames; + String defaultName = getName(); // TODO: replace with naming strategy class + String overriddenName; + boolean forceQuote; + + if (isIdProperty()) { // then the id is of a simple type (since it's not a composite primary key) + Optional optionalPrimaryKey = findAnnotation(PrimaryKey.class); + overriddenName = optionalPrimaryKey.map(PrimaryKey::value).orElse(""); + forceQuote = optionalPrimaryKey.map(PrimaryKey::forceQuote).orElse(false); + + } else if (isPrimaryKeyColumn()) { // then it's a simple type + Optional optionalPrimaryKey = findAnnotation(PrimaryKeyColumn.class); + overriddenName = optionalPrimaryKey.map(PrimaryKeyColumn::value).orElse(""); + forceQuote = optionalPrimaryKey.map(PrimaryKeyColumn::forceQuote).orElse(false); + + } else { // then it's a vanilla column with the assumption that it's mapped to a single column + Optional optionalColumn = findAnnotation(Column.class); + overriddenName = optionalColumn.map(Column::value).orElse(""); + forceQuote = optionalColumn.map(Column::forceQuote).orElse(false); + } + + return createColumnName(defaultName, overriddenName, forceQuote); } - protected CqlIdentifier createColumnName(String defaultName, String overriddenName, boolean forceQuote) { + private CqlIdentifier createColumnName(String defaultName, String overriddenName, boolean forceQuote) { String name = defaultName; @@ -412,47 +365,15 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return cqlId(name, forceQuote); } - protected void addCompositePrimaryKeyColumnNames(CassandraPersistentEntity compositePrimaryKeyEntity, - final List columnNames) { - - compositePrimaryKeyEntity.getPersistentProperties().forEach(property -> { - if (property.isCompositePrimaryKey()) { - addCompositePrimaryKeyColumnNames(property.getCompositePrimaryKeyEntity(), columnNames); - } else { - columnNames.add(property.getColumnName()); - } - }); - } - /* (non-Javadoc) * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#setColumnName(org.springframework.cassandra.core.cql.CqlIdentifier) */ @Override public void setColumnName(CqlIdentifier columnName) { - Assert.notNull(columnName, "columnName must not be null"); + Assert.notNull(columnName, "ColumnName must not be null"); - setColumnNames(Collections.singletonList(columnName)); - } - - /* (non-Javadoc) - * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#setColumnNames(java.util.List) - */ - @Override - public void setColumnNames(List columnNames) { - - Assert.notNull(columnNames, "List of column names must not be null"); - - // force calculation of columnNames if not known yet - getColumnNames(); - - Assert.state(this.columnNames.size() == columnNames.size(), - String.format( - "Property [%s] of entity [%s] is mapped to [%s] column%s, but given column name list has size [%s]", - getName(), getOwner().getType().getName(), this.columnNames.size(), this.columnNames.size() == 1 ? "" : "s", - columnNames.size())); - - this.columnNames = Collections.unmodifiableList(new ArrayList<>(columnNames)); + this.columnName = columnName; } /* (non-Javadoc) @@ -461,45 +382,17 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP @Override public void setForceQuote(boolean forceQuote) { - if (this.forceQuote != null && this.forceQuote == forceQuote) { - return; - } else { - this.forceQuote = forceQuote; + boolean changed = !this.forceQuote.isPresent() || this.forceQuote.filter(v -> v != forceQuote).isPresent(); + + this.forceQuote = Optional.of(forceQuote); + + if (changed) { + + CqlIdentifier columnName = getColumnName(); + if (columnName != null) { + setColumnName(cqlId(columnName.getUnquoted(), forceQuote)); + } } - - List columnNames = getColumnNames() // - .stream() // - .map(CqlIdentifier::getUnquoted) // - .map(name -> cqlId(name, forceQuote)) // - .collect(Collectors.toList()); - - setColumnNames(columnNames); - } - - /* (non-Javadoc) - * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#getCompositePrimaryKeyProperties() - */ - @Override - public List getCompositePrimaryKeyProperties() { - - Assert.state(isCompositePrimaryKey(), - String.format("[%s] does not represent a composite primary key property", getName())); - - return getCompositePrimaryKeyEntity().getCompositePrimaryKeyProperties(); - } - - /* (non-Javadoc) - * @see org.springframework.data.cassandra.mapping.CassandraPersistentProperty#getCompositePrimaryKeyEntity() - */ - @Override - public CassandraPersistentEntity getCompositePrimaryKeyEntity() { - - MappingContext, CassandraPersistentProperty> mappingContext = getOwner() - .getMappingContext(); - - Assert.state(mappingContext != null, "CassandraMappingContext needed"); - - return mappingContext.getRequiredPersistentEntity(getCompositePrimaryKeyTypeInformation()); } /* (non-Javadoc) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java index 4f4ab75d5..170745210 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java @@ -254,10 +254,6 @@ public class CassandraMappingContext entities.add(entity); if (!entity.isUserDefinedType()) { - if (entity.isCompositePrimaryKey()) { - primaryKeyEntities.add(entity); - } - entity.findAnnotation(Table.class).ifPresent(table -> tableEntities.add(entity)); } }); @@ -286,10 +282,10 @@ public class CassandraMappingContext BasicCassandraPersistentEntity entity; if (userDefinedType != null) { - entity = new CassandraUserTypePersistentEntity<>(typeInformation, this, verifier, userTypeResolver); + entity = new CassandraUserTypePersistentEntity<>(typeInformation, verifier, userTypeResolver); } else { - entity = new BasicCassandraPersistentEntity<>(typeInformation, this, verifier); + entity = new BasicCassandraPersistentEntity<>(typeInformation, verifier); } if (context != null) { @@ -442,10 +438,6 @@ public class CassandraMappingContext private DataType getDataTypeWithUserTypeFactory(CassandraPersistentProperty property, DataTypeProvider dataTypeProvider) { - if (property.isCompositePrimaryKey()) { - return property.getDataType(); - } - if (property.findAnnotation(CassandraType.class).isPresent()) { return property.getDataType(); } @@ -464,6 +456,7 @@ public class CassandraMappingContext return customConversions.getCustomWriteTarget(property.getType()) // .map(CassandraSimpleTypeHolder::getDataTypeFor) // .orElseGet(() -> customConversions.getCustomWriteTarget(property.getActualType()) // + .filter(it -> !property.isMapLike()) // .map(it -> { if (property.isCollectionLike()) { @@ -478,9 +471,26 @@ public class CassandraMappingContext } return getDataTypeFor(it); - }).orElseGet(property::getDataType) + }).orElseGet(() -> { - ); + if (property.isMapLike()) { + + Class keyType = property.getComponentType().get(); + Class valueType = property.getMapValueType().get(); + return DataType.map(getDataType(keyType, dataTypeProvider), getDataType(valueType, dataTypeProvider)); + } + + return property.getDataType(); + })); + + } + + private DataType getDataType(Class type, DataTypeProvider dataTypeProvider) { + + return getPersistentEntity(type) // + .filter(CassandraPersistentEntity::isUserDefinedType) // + .map(dataTypeProvider::getDataType) // + .orElseGet(() -> getDataType(type)); } private DataType getUserDataType(CassandraPersistentProperty property, DataTypeProvider dataTypeProvider, diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java index 80492cdf5..0a6521164 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java @@ -15,13 +15,10 @@ */ package org.springframework.data.cassandra.core.mapping; -import java.util.List; - import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.data.cql.core.CqlIdentifier; import org.springframework.data.mapping.PersistentEntity; -import org.springframework.data.mapping.context.MappingContext; import com.datastax.driver.core.UserType; @@ -40,9 +37,6 @@ public interface CassandraPersistentEntity */ boolean isCompositePrimaryKey(); - // TODO: return rather a Stream, rename to "getPrimaryKeyProperties" - List getCompositePrimaryKeyProperties(); - /** * Returns the table name to which the entity shall be persisted. */ @@ -76,8 +70,6 @@ public interface CassandraPersistentEntity */ UserType getUserType(); - // TODO: Review if that's required or it can be handled in a different way - MappingContext, CassandraPersistentProperty> getMappingContext(); ApplicationContext getApplicationContext(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentProperty.java index 343f57796..96a92a588 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentProperty.java @@ -15,7 +15,6 @@ */ package org.springframework.data.cassandra.core.mapping; -import java.util.List; import java.util.Optional; import org.springframework.context.ApplicationContextAware; @@ -24,7 +23,6 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.cql.core.CqlIdentifier; import org.springframework.data.cql.core.Ordering; import org.springframework.data.mapping.PersistentProperty; -import org.springframework.data.util.TypeInformation; import com.datastax.driver.core.DataType; @@ -41,40 +39,10 @@ public interface CassandraPersistentProperty extends PersistentProperty, ApplicationContextAware { /** - * Whether the property is a composite primary key. - */ - boolean isCompositePrimaryKey(); - - /** - * Returns a {@link CassandraPersistentEntity} representing the composite primary key class of this entity, or null if - * this class does not use a composite primary key. - */ - CassandraPersistentEntity getCompositePrimaryKeyEntity(); - - /** - * Returns a {@link TypeInformation} representing the type of the composite primary key class of this entity, or null - * if this class does not use a composite primary key. - */ - TypeInformation getCompositePrimaryKeyTypeInformation(); - - /** - * Gets the list of composite primary key properties that this composite primary key field is a placeholder for. - */ - List getCompositePrimaryKeyProperties(); - - /** - * The name of the single column to which the property is persisted. This is a convenience method when the caller - * knows that the property is mapped to a single column. Throws {@link IllegalStateException} if this property is - * mapped to multiple columns. + * The name of the single column to which the property is persisted. */ CqlIdentifier getColumnName(); - /** - * The names of the columns to which the property is persisted if this is a composite primary key property. Never - * returns null. - */ - List getColumnNames(); - /** * The ordering (ascending or descending) for the column. Valid only for primary key columns; returns null for * non-primary key columns. @@ -96,14 +64,9 @@ public interface CassandraPersistentProperty boolean isIndexed(); /** - * Whether the property is a partition key column. + * Whether the property is a composite primary key. */ - boolean isPartitionKeyColumn(); - - /** - * Whether the property is a cluster key column. - */ - boolean isClusterKeyColumn(); + boolean isCompositePrimaryKey(); /** * Whether the property is a partition key column or a cluster key column @@ -113,6 +76,16 @@ public interface CassandraPersistentProperty */ boolean isPrimaryKeyColumn(); + /** + * Whether the property is a partition key column. + */ + boolean isPartitionKeyColumn(); + + /** + * Whether the property is a cluster key column. + */ + boolean isClusterKeyColumn(); + @Override CassandraPersistentEntity getOwner(); @@ -120,7 +93,7 @@ public interface CassandraPersistentProperty * Whether to force-quote the column names of this property. * * @param forceQuote - * @see CassandraPersistentProperty#getColumnNames() + * @see CassandraPersistentProperty#getColumnName() */ void setForceQuote(boolean forceQuote); @@ -129,18 +102,10 @@ public interface CassandraPersistentProperty * property is not mapped by a single column, throws {@link IllegalStateException}. If the given column name is null, * {@link IllegalArgumentException} is thrown. * - * @param columnName + * @param columnName must not be {@literal null}. */ void setColumnName(CqlIdentifier columnName); - /** - * Sets this property's column names to the collection given. The given collection must have the same size as this - * property's current list of column names, and must contain no {@code null} elements. - * - * @param columnName - */ - void setColumnNames(List columnNames); - /** * Returns whether the property is a {@link java.util.Map}. * diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntity.java index 032084860..f9fb98d0b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntity.java @@ -18,7 +18,6 @@ package org.springframework.data.cassandra.core.mapping; import java.util.Optional; import org.springframework.data.cql.core.CqlIdentifier; -import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; @@ -45,15 +44,13 @@ public class CassandraUserTypePersistentEntity extends BasicCassandraPersiste * Create a new {@link CassandraUserTypePersistentEntity}. * * @param typeInformation must not be {@literal null}. - * @param mappingContext must not be {@literal null}. * @param verifier must not be {@literal null}. * @param resolver must not be {@literal null}. */ public CassandraUserTypePersistentEntity(TypeInformation typeInformation, - MappingContext, CassandraPersistentProperty> mappingContext, CassandraPersistentEntityMetadataVerifier verifier, UserTypeResolver resolver) { - super(typeInformation, mappingContext, verifier); + super(typeInformation, verifier); Assert.notNull(resolver, "UserTypeResolver must not be null"); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraCompositePrimaryKeyUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraCompositePrimaryKeyUnitTests.java index 3d5d36963..e57538773 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraCompositePrimaryKeyUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraCompositePrimaryKeyUnitTests.java @@ -16,18 +16,16 @@ package org.springframework.data.cassandra.core.mapping; import static org.assertj.core.api.Assertions.*; -import static org.springframework.data.cql.core.CqlIdentifier.*; + +import lombok.EqualsAndHashCode; import java.io.Serializable; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.List; import org.junit.Before; import org.junit.Test; -import org.springframework.data.cql.core.CqlIdentifier; import org.springframework.data.cql.core.PrimaryKeyType; import org.springframework.data.cql.core.keyspace.ColumnSpecification; import org.springframework.data.cql.core.keyspace.CreateTableSpecification; @@ -48,51 +46,20 @@ public class CassandraCompositePrimaryKeyUnitTests { private static final CassandraSimpleTypeHolder SIMPLE_TYPE_HOLDER = new CassandraSimpleTypeHolder(); @PrimaryKeyClass - static class Key implements Serializable { + @EqualsAndHashCode + static class CompositeKey implements Serializable { private static final long serialVersionUID = 1L; @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) String z; @PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.CLUSTERED) String a; - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((a == null) ? 0 : a.hashCode()); - result = prime * result + ((z == null) ? 0 : z.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Key other = (Key) obj; - if (a == null) { - if (other.a != null) - return false; - } else if (!a.equals(other.a)) - return false; - if (z == null) { - if (other.z != null) - return false; - } else if (!z.equals(other.z)) - return false; - return true; - } - } @Table - static class Thing { + static class TypeWithCompositeKey { - @PrimaryKey Key id; + @PrimaryKey CompositeKey id; Date time; @@ -100,36 +67,29 @@ public class CassandraCompositePrimaryKeyUnitTests { } CassandraMappingContext context; - CassandraPersistentEntity thing; + + CassandraPersistentEntity entity; + CassandraPersistentEntity key; @Before public void setup() { + context = new CassandraMappingContext(); - thing = context.getRequiredPersistentEntity(ClassTypeInformation.from(Thing.class)); - key = context.getRequiredPersistentEntity(ClassTypeInformation.from(Key.class)); + entity = context.getRequiredPersistentEntity(ClassTypeInformation.from(TypeWithCompositeKey.class)); + key = context.getRequiredPersistentEntity(ClassTypeInformation.from(CompositeKey.class)); } @Test public void validateMappingInfo() { - Field field = ReflectionUtils.findField(Thing.class, "id"); - CassandraPersistentProperty property = new BasicCassandraPersistentProperty(Property.of(field), thing, + Field field = ReflectionUtils.findField(TypeWithCompositeKey.class, "id"); + CassandraPersistentProperty property = new BasicCassandraPersistentProperty(Property.of(field), entity, SIMPLE_TYPE_HOLDER); assertThat(property.isIdProperty()).isTrue(); assertThat(property.isCompositePrimaryKey()).isTrue(); - List expectedColumnNames = Arrays.asList(cqlId("z"), cqlId("a")); - assertThat(expectedColumnNames.equals(property.getColumnNames())).isTrue(); - - List actualColumnNames = new ArrayList<>(); - List properties = property.getCompositePrimaryKeyProperties(); - for (CassandraPersistentProperty p : properties) { - actualColumnNames.addAll(p.getColumnNames()); - } - assertThat(expectedColumnNames.equals(actualColumnNames)).isTrue(); - - CreateTableSpecification spec = context.getCreateTableSpecificationFor(thing); + CreateTableSpecification spec = context.getCreateTableSpecificationFor(entity); List partitionKeyColumns = spec.getPartitionKeyColumns(); assertThat(partitionKeyColumns).hasSize(1); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContextUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContextUnitTests.java index 21340a17a..acce95782 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContextUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContextUnitTests.java @@ -93,11 +93,6 @@ public class CassandraMappingContextUnitTests { assertThat(idProperty).hasValueSatisfying(actual -> { assertThat(actual.getColumnName().toCql()).isEqualTo("foo"); - - List columnNames = actual.getColumnNames(); - - assertThat(columnNames).hasSize(1); - assertThat(columnNames.get(0).toCql()).isEqualTo("foo"); }); } @@ -178,7 +173,6 @@ public class CassandraMappingContextUnitTests { .isTrue(); assertThat(primaryKeyClass.isCompositePrimaryKey()).isTrue(); - assertThat(primaryKeyClass.getCompositePrimaryKeyProperties()).hasSize(2); CassandraPersistentProperty firstname = primaryKeyClass.getRequiredPersistentProperty("firstname"); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntityUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntityUnitTests.java index c1ee1c195..a8744bad6 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntityUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntityUnitTests.java @@ -38,7 +38,6 @@ import org.springframework.data.util.ClassTypeInformation; @RunWith(MockitoJUnitRunner.class) public class CassandraUserTypePersistentEntityUnitTests { - @Mock CassandraMappingContext mappingContextMock; @Mock UserTypeResolver userTypeResolverMock; @Test // DATACASS-172 @@ -85,8 +84,7 @@ public class CassandraUserTypePersistentEntityUnitTests { } private CassandraUserTypePersistentEntity getEntity(Class entityClass) { - return new CassandraUserTypePersistentEntity<>(ClassTypeInformation.from(entityClass), mappingContextMock, null, - userTypeResolverMock); + return new CassandraUserTypePersistentEntity<>(ClassTypeInformation.from(entityClass), null, userTypeResolverMock); } @UserDefinedType diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/ForceQuotedPropertiesSimpleUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/ForceQuotedPropertiesSimpleUnitTests.java index 7fd3d03c6..c3bd44b50 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/ForceQuotedPropertiesSimpleUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/ForceQuotedPropertiesSimpleUnitTests.java @@ -19,8 +19,6 @@ import static org.assertj.core.api.Assertions.*; import static org.springframework.data.cql.core.CqlIdentifier.*; import java.io.Serializable; -import java.util.Arrays; -import java.util.List; import org.junit.Test; import org.springframework.data.cql.core.CqlIdentifier; @@ -110,12 +108,9 @@ public class ForceQuotedPropertiesSimpleUnitTests { CassandraPersistentProperty stringOne = key.getRequiredPersistentProperty("stringOne"); assertThat(stringZero.getColumnName().toCql()).isEqualTo("\"stringZero\""); + assertThat(stringZero.getColumnName()).isEqualTo(quotedCqlId("stringZero")); assertThat(stringOne.getColumnName().toCql()).isEqualTo("\"stringOne\""); - - List names = Arrays.asList(quotedCqlId("stringZero"), quotedCqlId("stringOne")); - CassandraPersistentEntity entity = context.getRequiredPersistentEntity(ImplicitComposite.class); - - assertThat(entity.getRequiredPersistentProperty("primaryKey").getColumnNames()).isEqualTo(names); + assertThat(stringOne.getColumnName()).isEqualTo(quotedCqlId("stringOne")); } @PrimaryKeyClass @@ -148,11 +143,6 @@ public class ForceQuotedPropertiesSimpleUnitTests { assertThat(stringOne.getColumnName()).isEqualTo(CqlIdentifier.cqlId("stringOne")); assertThat(stringZero.getColumnName().toCql()).isEqualTo("stringzero"); assertThat(stringOne.getColumnName().toCql()).isEqualTo("stringone"); - - List names = Arrays.asList(cqlId("stringZero"), cqlId("stringOne")); - CassandraPersistentEntity entity = context.getRequiredPersistentEntity(DefaultComposite.class); - - assertThat(entity.getRequiredPersistentProperty("primaryKey").getColumnNames()).isEqualTo(names); } @PrimaryKeyClass @@ -187,11 +177,6 @@ public class ForceQuotedPropertiesSimpleUnitTests { assertThat(stringZero.getColumnName().toCql()).isEqualTo("\"" + EXPLICIT_KEY_0 + "\""); assertThat(stringOne.getColumnName().toCql()).isEqualTo("\"" + EXPLICIT_KEY_1 + "\""); - - List names = Arrays.asList(quotedCqlId(EXPLICIT_KEY_0), quotedCqlId(EXPLICIT_KEY_1)); - CassandraPersistentEntity entity = context.getRequiredPersistentEntity(ExplicitComposite.class); - - assertThat(entity.getRequiredPersistentProperty("primaryKey").getColumnNames()).isEqualTo(names); } @PrimaryKeyClass diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreatorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreatorUnitTests.java index 764a13cbd..62a7c6fb3 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreatorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreatorUnitTests.java @@ -269,7 +269,7 @@ public class CassandraQueryCreatorUnitTests { assertThat(query).isEqualTo("SELECT * FROM key WHERE firstname='Walter';"); } - @Test(expected = IllegalStateException.class) // DATACASS-7 + @Test(expected = IllegalArgumentException.class) // DATACASS-7 public void createsFindByPrimaryKey2PartCorrectly() { createQuery("findByKey", TypeWithCompositeId.class, new Key()); }