From f96e9383f34c15060326ba62fdc45c85ea847723 Mon Sep 17 00:00:00 2001 From: John Blum Date: Sun, 24 Jul 2016 19:17:10 -0700 Subject: [PATCH] DATACASS-7 - Polish. Origin pull request: #74. --- .../mapping/BasicCassandraMappingContext.java | 52 ++-- ...andraPersistentEntityMetadataVerifier.java | 230 ++++++++---------- .../BasicCassandraPersistentProperty.java | 68 +++--- .../mapping/CassandraPersistentProperty.java | 32 ++- .../query/AbstractCassandraQuery.java | 119 ++++----- .../repository/query/CassandraParameters.java | 15 +- .../CassandraParametersParameterAccessor.java | 34 +-- .../query/CassandraQueryCreator.java | 103 ++++---- .../query/CassandraQueryMethod.java | 47 ++-- .../query/ConvertingParameterAccessor.java | 38 ++- .../query/PartTreeCassandraQuery.java | 26 +- .../query/SimpleCassandraEntityMetadata.java | 17 +- .../support/CassandraRepositoryFactory.java | 37 ++- .../CassandraRepositoryFactoryBean.java | 28 ++- .../query/CassandraParametersUnitTests.java | 3 +- .../query/CassandraQueryCreatorUnitTests.java | 65 ++--- .../query/CassandraQueryMethodUnitTests.java | 10 +- .../ConvertingParameterAccessorUnitTests.java | 99 ++++---- .../PartTreeCassandraQueryUnitTests.java | 44 ++-- .../CassandraRepositoryFactoryUnitTests.java | 33 ++- .../QueryDerivationIntegrationTests.java | 46 ++-- .../integration/support/CassandraVersion.java | 5 +- 22 files changed, 578 insertions(+), 573 deletions(-) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraMappingContext.java index 3376232b3..755bc6f3e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraMappingContext.java @@ -83,7 +83,6 @@ public class BasicCassandraMappingContext * Creates a new {@link BasicCassandraMappingContext}. */ public BasicCassandraMappingContext() { - setCustomConversions(new CustomConversions(Collections.EMPTY_LIST)); setSimpleTypeHolder(CassandraSimpleTypeHolder.HOLDER); } @@ -95,7 +94,6 @@ public class BasicCassandraMappingContext * @since 1.5 */ public void setCustomConversions(CustomConversions customConversions) { - Assert.notNull(customConversions, "CustomConversions must not be null"); this.customConversions = customConversions; @@ -127,6 +125,7 @@ public class BasicCassandraMappingContext if (includePrimaryKeyTypes) { return super.getPersistentEntities(); } + return Collections.unmodifiableSet(nonPrimaryKeyEntities); } @@ -296,55 +295,50 @@ public class BasicCassandraMappingContext public DataType getDataType(Class type) { return (customConversions.hasCustomWriteTarget(type) - ? getDataTypeFor(customConversions.getCustomWriteTarget(type)) - : getDataTypeFor(type)); + ? getDataTypeFor(customConversions.getCustomWriteTarget(type)) : getDataTypeFor(type)); } public void setMapping(Mapping mapping) { - Assert.notNull(mapping, "Mapping must not be null"); this.mapping = mapping; } protected void processMappingOverrides() { - if (mapping != null) { for (EntityMapping entityMapping : mapping.getEntityMappings()) { - if (entityMapping == null) { - continue; - } + if (entityMapping != null) { + String entityClassName = entityMapping.getEntityClassName(); - String entityClassName = entityMapping.getEntityClassName(); + try { + Class entityClass = ClassUtils.forName(entityClassName, beanClassLoader); - try { - Class entityClass = ClassUtils.forName(entityClassName, beanClassLoader); + CassandraPersistentEntity entity = getPersistentEntity(entityClass); - CassandraPersistentEntity entity = getPersistentEntity(entityClass); + if (entity == null) { + throw new IllegalStateException(String.format( + "Unknown persistent entity class name [%s]", entityClassName)); + } - if (entity == null) { - throw new IllegalStateException(String.format("unknown persistent entity class name [%s]", entityClassName)); + String tableName = entityMapping.getTableName(); + + if (StringUtils.hasText(tableName)) { + entity.setTableName(cqlId(tableName, Boolean.valueOf(entityMapping.getForceQuote()))); + } + + processMappingOverrides(entity, entityMapping); + + } catch (ClassNotFoundException e) { + throw new IllegalStateException(String.format( + "unknown persistent entity name [%s]", entityClassName), e); } - - String tableName = entityMapping.getTableName(); - - if (StringUtils.hasText(tableName)) { - entity.setTableName(cqlId(tableName, Boolean.valueOf(entityMapping.getForceQuote()))); - } - - processMappingOverrides(entity, entityMapping); - - } catch (ClassNotFoundException e) { - throw new IllegalStateException(String.format( - "unknown persistent entity name [%s]", entityClassName), e); } } } } protected void processMappingOverrides(CassandraPersistentEntity entity, EntityMapping entityMapping) { - for (PropertyMapping mapping : entityMapping.getPropertyMappings().values()) { processMappingOverride(entity, mapping); } @@ -356,7 +350,7 @@ public class BasicCassandraMappingContext if (property == null) { throw new IllegalArgumentException(String.format("Entity class [%s] has no persistent property named [%s]", - entity.getType().getName(), mapping.getPropertyName())); + entity.getType().getName(), mapping.getPropertyName())); } boolean forceQuote = false; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntityMetadataVerifier.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntityMetadataVerifier.java index 204ca8ba9..2d4a03fdd 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntityMetadataVerifier.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntityMetadataVerifier.java @@ -32,6 +32,7 @@ import org.springframework.data.mapping.model.MappingException; * * @author Matthew T Adams * @author David Webb + * @author John Blum */ public class BasicCassandraPersistentEntityMetadataVerifier implements CassandraPersistentEntityMetadataVerifier { @@ -40,14 +41,15 @@ public class BasicCassandraPersistentEntityMetadataVerifier implements Cassandra protected boolean strict = false; @Override + @SuppressWarnings("all") public void verify(CassandraPersistentEntity entity) throws MappingException { - if(entity.getType().isInterface()){ + if (entity.getType().isInterface()){ return; } - VerifierMappingExceptions exceptions = new VerifierMappingExceptions(entity, - String.format("Mapping Exceptions from BasicCassandraPersistentEntityMetadataVerifier for %s", entity.getName())); + VerifierMappingExceptions exceptions = new VerifierMappingExceptions(entity, String.format( + "Mapping Exceptions from BasicCassandraPersistentEntityMetadataVerifier for %s", entity.getName())); final List idProperties = new ArrayList(); final List compositePrimaryKeys = new ArrayList(); @@ -55,49 +57,41 @@ public class BasicCassandraPersistentEntityMetadataVerifier implements Cassandra final List clusterKeyColumns = new ArrayList(); final List primaryKeyColumns = new ArrayList(); - /* - * Determine how this type is annotated - */ - Class thisType = entity.getType(); + Class entityType = entity.getType(); - boolean isTable = (thisType.isAnnotationPresent(Table.class) || thisType.isAnnotationPresent(Persistent.class)); - boolean isPrimaryKeyClass = thisType.isAnnotationPresent(PrimaryKeyClass.class); + boolean isTable = (entityType.isAnnotationPresent(Table.class) + || entityType.isAnnotationPresent(Persistent.class)); - /* - * Ensure that this is not both a @Table(@Persistent) and a @PrimaryKey - */ + boolean isPrimaryKeyClass = entityType.isAnnotationPresent(PrimaryKeyClass.class); + + // Ensure entity is not both a @Table(@Persistent) and a @PrimaryKey if (isTable && isPrimaryKeyClass) { exceptions.add(new MappingException("Entity cannot be of type Table and PrimaryKey")); throw exceptions; } - /* - * Ensure that this is either a @Table(@Persistent) or a @PrimaryKey - */ + // Ensure entity is either a @Table/@Persistent or a @PrimaryKey if (!isTable && !isPrimaryKeyClass) { exceptions.add(new MappingException( - "Cassandra entities must have the @Table, @Persistent or @PrimaryKeyClass Annotation")); + "Cassandra entities must have the @Table, @Persistent or @PrimaryKeyClass Annotation")); throw exceptions; } - /* - * Parse the properties - */ + // Parse entity properties entity.doWithProperties(new PropertyHandler() { @Override - public void doWithPersistentProperty(CassandraPersistentProperty p) { - - if (p.isIdProperty()) { - idProperties.add(p); - } else if (p.isCompositePrimaryKey()) { - compositePrimaryKeys.add(p); - } else if (p.isPartitionKeyColumn()) { - partitionKeyColumns.add(p); - primaryKeyColumns.add(p); - } else if (p.isClusterKeyColumn()) { - clusterKeyColumns.add(p); - primaryKeyColumns.add(p); + public void doWithPersistentProperty(CassandraPersistentProperty property) { + if (property.isIdProperty()) { + idProperties.add(property); + } else if (property.isClusterKeyColumn()) { + clusterKeyColumns.add(property); + primaryKeyColumns.add(property); + } else if (property.isCompositePrimaryKey()) { + compositePrimaryKeys.add(property); + } else if (property.isPartitionKeyColumn()) { + partitionKeyColumns.add(property); + primaryKeyColumns.add(property); } } }); @@ -106,92 +100,51 @@ public class BasicCassandraPersistentEntityMetadataVerifier implements Cassandra final int partitionKeyColumnCount = partitionKeyColumns.size(); final int primaryKeyColumnCount = primaryKeyColumns.size(); - /* - * Perform rules verification on PrimaryKeyClass - */ + // Perform rules verification on PrimaryKeyClass if (isPrimaryKeyClass) { - /* - * Must have at least 1 attribute annotated with @PrimaryKeyColumn - */ + // Must have at least 1 attribute annotated with @PrimaryKeyColumn if (primaryKeyColumnCount == 0) { exceptions.add(new MappingException(String.format( - "composite primary key type [%s] has no fields annotated with @%s", entity.getType().getName(), + "Composite primary key type [%s] has no fields annotated with @%s", entity.getType().getName(), PrimaryKeyColumn.class.getSimpleName()))); } - /* - * At least one of the PrimaryKeyColumns must have a type PARTIONED - */ + // At least one of the PrimaryKeyColumns must have a type PARTIONED if (partitionKeyColumnCount == 0) { exceptions.add(new MappingException( - "At least one of the @PrimaryKeyColumn annotation must have a type of PARTITIONED")); + "At least one of the @PrimaryKeyColumn annotations must have a type of PARTITIONED")); } - /* - * Cannot have any Id or PrimaryKey Annotations - */ + // Cannot have any Id or PrimaryKey Annotations if (idPropertyCount > 0) { exceptions.add(new MappingException( - "Annotations @Id and @PrimaryKey are invalid for type annotated with @PrimaryKeyClass")); + "Annotations @Id and @PrimaryKey are invalid for type annotated with @PrimaryKeyClass")); } - /* - * Ensure that PrimaryKeyColumn is a supported Type. - */ - for (CassandraPersistentProperty p : primaryKeyColumns) { - if (CassandraSimpleTypeHolder.getDataTypeFor(p.getType()) == null) { - exceptions.add(new MappingException("Fields annotated with @PrimaryKeyColumn must be simple CassandraTypes")); + // Ensure that PrimaryKeyColumn is a supported Type. + for (CassandraPersistentProperty property : primaryKeyColumns) { + if (CassandraSimpleTypeHolder.getDataTypeFor(property.getType()) == null) { + exceptions.add(new MappingException( + "Fields annotated with @PrimaryKeyColumn must be simple CassandraTypes")); } } - /* - * Ensure PrimaryKeyClass is Serializable - */ - if (!Serializable.class.isAssignableFrom(thisType)) { + // Ensure PrimaryKeyClass is Serializable + if (!Serializable.class.isAssignableFrom(entityType)) { exceptions.add(new MappingException("@PrimaryKeyClass must be Serializable")); } - /* - * Ensure PrimaryKeyClass only extends Object - */ - if (!thisType.getSuperclass().equals(Object.class)) { + // Ensure PrimaryKeyClass only extends Object + if (!entityType.getSuperclass().equals(Object.class)) { exceptions.add(new MappingException("@PrimaryKeyClass must only extend Object")); } - /* - * Check that PrimaryKeyClass overrides "boolean equals(Object)" - */ - try { - Method equalsMethod = thisType.getDeclaredMethod("equals", Object.class); - if (equalsMethod == null || !equalsMethod.getDeclaringClass().equals(thisType)) { - throw new NoSuchMethodException(); - } - } catch (NoSuchMethodException e) { - String message = "@PrimaryKeyClass should override 'boolean equals(Object)' method and use all @PrimaryKeyColumn fields"; - if (strict) { - exceptions.add(new MappingException(message, e)); - } else { - log.warn(message); - } - } + // Check that PrimaryKeyClass overrides "boolean equals(Object)" + verifyMethodPresent(entityType, "equals", "boolean equals(Object)", exceptions); - /* - * Ensure PrimaryKeyClass overrides "int hashCode()" - */ - try { - Method hashCodeMethod = thisType.getDeclaredMethod("hashCode", (Class[]) null); - if (hashCodeMethod == null || !hashCodeMethod.getDeclaringClass().equals(thisType)) { - throw new NoSuchMethodException(); - } - } catch (NoSuchMethodException e) { - String message = "@PrimaryKeyClass should override 'int hashCode()' method and use all @PrimaryKeyColumn fields"; - if (strict) { - exceptions.add(new MappingException(message, e)); - } else { - log.warn(message); - } - } + // Ensure PrimaryKeyClass overrides "int hashCode()" + verifyMethodPresent(entityType, "hashCode", "int hashCode()", exceptions); } /* @@ -199,75 +152,88 @@ public class BasicCassandraPersistentEntityMetadataVerifier implements Cassandra */ if (isTable) { - /* - * TODO Verify annotation values with CqlIndentifier - */ + // TODO Verify annotation values with CqlIndentifier - /* - * Ensure only one PK or at least one partitioned PKC and not both PK(s) & PKC(s) - */ + // Ensure only one PK or at least one partitioned PK Column and not both PK(s) & PK Column(s) exist if (primaryKeyColumnCount == 0) { - /* - * Can only have one PK. - */ + // Can only have one PK if (idPropertyCount != 1) { - exceptions - .add(new MappingException(String.format( - "@Table/@Persistent types must have only one @PrimaryKey attribute, if any. Found %s.", - idPropertyCount))); + exceptions.add(new MappingException(String.format( + "@Table/@Persistent types must have only one @PrimaryKey attribute, if any; Found %s", + idPropertyCount))); + throw exceptions; } - /* - * Ensure that Id is a supported Type. At the point there is only 1. - */ - Class typeClass = idProperties.get(0).getType(); - if (!typeClass.isAnnotationPresent(PrimaryKeyClass.class) - && CassandraSimpleTypeHolder.getDataTypeFor(typeClass) == null) { + + // Ensure that Id is a supported Type. At this point there is only 1. + Class idType = idProperties.get(0).getType(); + + if (!idType.isAnnotationPresent(PrimaryKeyClass.class) + && CassandraSimpleTypeHolder.getDataTypeFor(idType) == null) { + exceptions.add(new MappingException( - "Fields annotated with @PrimaryKey must be simple CassandraTypes or @PrimaryKeyClass type")); + "Fields annotated with @PrimaryKey must be simple CassandraTypes or @PrimaryKeyClass type")); } } else if (idPropertyCount > 0) { - /* - * Then we have both PK(s) & PKC(s) - */ - exceptions - .add(new MappingException( - String - .format( - "@Table/@Persistent types must not define both @PrimaryKeyColumn field%s (found %s) and @PrimaryKey field%s (found %s)", - primaryKeyColumnCount == 1 ? "" : "s", primaryKeyColumnCount, idPropertyCount == 1 ? "" : "s", - idPropertyCount))); + // Then we have both PK(s) & PK Column(s) + exceptions.add(new MappingException(String.format( + "@Table/@Persistent types must not define both @PrimaryKeyColumn field(s) (found %s) and @PrimaryKey field(s) (found %s)", + primaryKeyColumnCount, idPropertyCount))); + throw exceptions; } else { - /* - * We have no PKs & only PKC(s) -- ensure at least one is of type PARTITIONED - */ + // We have no PKs & only PK Column(s); ensure at least one is of type PARTITIONED if (partitionKeyColumnCount == 0) { - exceptions.add(new MappingException(String - .format("@Table/@Persistent types must define at least one @PrimaryKeyColumn of type PARTITIONED"))); + exceptions.add(new MappingException(String.format( + "@Table/@Persistent types must define at least one @PrimaryKeyColumn of type PARTITIONED"))); } } } - /* - * Determine whether or not to throw Exception based on errors found - */ + // Determine whether or not to throw Exception based on errors found if (exceptions.getCount() > 0) { log.error("Exceptions while verifying PersistentEntity", exceptions); throw exceptions; } } + boolean verifyMethodPresent(Class type, String methodName, String methodDescription, + VerifierMappingExceptions exceptions) { + try { + Method method = type.getDeclaredMethod(methodName, Object.class); + + if (method == null || !method.getDeclaringClass().equals(type)) { + throw new NoSuchMethodException(); + } + + return true; + } catch (NoSuchMethodException e) { + String message = String.format( + "@PrimaryKeyClass should override '%s' method and use all @PrimaryKeyColumn fields", + methodDescription); + + if (strict) { + exceptions.add(new MappingException(message, e)); + } else { + log.warn(message); + } + + return false; + } + } + /** - * @return Returns the strict. + * @return the setting for strict. */ + @SuppressWarnings("unused") public boolean isStrict() { return strict; } /** - * @param strict The strict to set. + * @param strict boolean setting for strict. */ + @SuppressWarnings("unused") public void setStrict(boolean strict) { this.strict = strict; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentProperty.java index 274d1ab03..e7e65c021 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentProperty.java @@ -22,6 +22,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; import org.springframework.cassandra.core.Ordering; @@ -41,6 +42,7 @@ import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import com.datastax.driver.core.DataType; @@ -52,6 +54,7 @@ import com.datastax.driver.core.DataType; * @author Matthew T. Adams * @author Antoine Toulme * @author Mark Paluch + * @author John Blum */ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentProperty implements CassandraPersistentProperty, ApplicationContextAware { @@ -154,8 +157,8 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP if (dataType == null) { throw new InvalidDataAccessApiUsageException(String.format( - "unknown type for property [%s], type [%s] in entity [%s]; only primitive types and collections or maps of primitive types are allowed", - getName(), getType(), getOwner().getName())); + "Unknown type [%s] for property [%s] in entity [%s]; only primitive types and Collections or Maps of primitive types are allowed", + getType(), getName(), getOwner().getName())); } return dataType; @@ -178,7 +181,6 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } if (isCollectionLike()) { - List> args = getTypeInformation().getTypeArguments(); ensureTypeArguments(args.size(), 1); @@ -220,20 +222,20 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return isAnnotationPresent(Indexed.class); } - @Override - public boolean isPartitionKeyColumn() { - - PrimaryKeyColumn primaryKeyColumn = findAnnotation(PrimaryKeyColumn.class); - - return (primaryKeyColumn != null && primaryKeyColumn.type() == PrimaryKeyType.PARTITIONED); - } - @Override public boolean isClusterKeyColumn() { PrimaryKeyColumn primaryKeyColumn = findAnnotation(PrimaryKeyColumn.class); - return (primaryKeyColumn != null && primaryKeyColumn.type() == PrimaryKeyType.CLUSTERED); + return (primaryKeyColumn != null && PrimaryKeyType.CLUSTERED.equals(primaryKeyColumn.type())); + } + + @Override + public boolean isPartitionKeyColumn() { + + PrimaryKeyColumn primaryKeyColumn = findAnnotation(PrimaryKeyColumn.class); + + return (primaryKeyColumn != null && PrimaryKeyType.PARTITIONED.equals(primaryKeyColumn.type())); } @Override @@ -241,12 +243,13 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return isAnnotationPresent(PrimaryKeyColumn.class); } - protected DataType getDataTypeFor(DataType.Name typeName) { - DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(typeName); + protected DataType getDataTypeFor(DataType.Name dataTypeName) { + + DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(dataTypeName); if (dataType == null) { throw new InvalidDataAccessApiUsageException(String.format( - "only primitive types are allowed inside collections for the property '%1$s' type is '%2$s' in the entity %3$s", + "Only primitive types are allowed inside Collections for property [%1$s] of type [%2$s] in entity [%3$s]", getName(), getType(), getOwner().getName())); } @@ -254,11 +257,12 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } protected DataType getDataTypeFor(Class javaType) { + DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(javaType); if (dataType == null) { throw new InvalidDataAccessApiUsageException(String.format( - "only primitive types are allowed inside collections for the property '%1$s' type is '%2$s' in the entity %3$s", + "Only primitive types are allowed inside Collections for property [%1$s] of type ['%2$s'] in entity [%3$s]", getName(), getType(), getOwner().getName())); } @@ -268,8 +272,8 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP protected void ensureTypeArguments(int args, int expected) { if (args != expected) { throw new InvalidDataAccessApiUsageException( - String.format("expected %1$s of typed arguments for the property '%2$s' type is '%3$s' in the entity %4$s", - expected, getName(), getType(), getOwner().getName())); + String.format("Expected [%1$s] typed arguments for property ['%2$s'] of type ['%3$s'] in entity [%4$s]", + expected, getName(), getType(), getOwner().getName())); } } @@ -320,7 +324,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP String name = defaultName; if (StringUtils.hasText(overriddenName)) { - name = (spelContext == null ? overriddenName : SpelUtils.evaluate(overriddenName, spelContext)); + name = (spelContext != null ? SpelUtils.evaluate(overriddenName, spelContext) : overriddenName); } return cqlId(name, forceQuote); @@ -331,11 +335,11 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP compositePrimaryKeyEntity.doWithProperties(new PropertyHandler() { @Override - public void doWithPersistentProperty(CassandraPersistentProperty p) { - if (p.isCompositePrimaryKey()) { - addCompositePrimaryKeyColumnNames(p.getCompositePrimaryKeyEntity(), columnNames); + public void doWithPersistentProperty(CassandraPersistentProperty property) { + if (property.isCompositePrimaryKey()) { + addCompositePrimaryKeyColumnNames(property.getCompositePrimaryKeyEntity(), columnNames); } else { - columnNames.add(p.getColumnName()); + columnNames.add(property.getColumnName()); } } }); @@ -353,14 +357,14 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP Assert.notNull(columnNames); - // force calculation of columnNames if not yet known + // force calculation of columnNames if not known yet getColumnNames(); if (this.columnNames.size() != columnNames.size()) { throw new IllegalStateException(String.format( - "property [%s] on 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())); + "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 = this.explicitColumnNames = @@ -390,8 +394,8 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP public List getCompositePrimaryKeyProperties() { if (!isCompositePrimaryKey()) { - throw new IllegalStateException( - String.format("[%s] does not represent a composite primary key property", getName())); + throw new IllegalStateException(String.format( + "[%s] does not represent a composite primary key property", getName())); } return getCompositePrimaryKeyEntity().getCompositePrimaryKeyProperties(); @@ -399,6 +403,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP @Override public CassandraPersistentEntity getCompositePrimaryKeyEntity() { + CassandraMappingContext mappingContext = getOwner().getMappingContext(); if (mappingContext == null) { @@ -417,4 +422,9 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP protected Association createAssociation() { return new Association(this, null); } + + @Override + public boolean isMapLike() { + return ClassUtils.isAssignable(Map.class, getType()); + } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java index 6ac2d502b..f9c704b8c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java @@ -1,12 +1,12 @@ /* * Copyright 2013-2016 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. @@ -29,11 +29,12 @@ import com.datastax.driver.core.DataType; /** * Cassandra specific {@link org.springframework.data.mapping.PersistentProperty} extension. - * + * * @author Alex Shvid * @author Matthew T. Adams * @author David T. Webb * @author Mark Paluch + * @author John Blum */ public interface CassandraPersistentProperty extends PersistentProperty, ApplicationContextAware { @@ -81,7 +82,7 @@ public interface CassandraPersistentProperty /** * The column's data type. Not valid for a composite primary key. - * + * * @return the Cassandra {@link DataType} * @throws InvalidDataAccessApiUsageException if the {@link DataType} cannot be resolved * @see CassandraType @@ -105,7 +106,7 @@ public interface CassandraPersistentProperty /** * Whether the property is a partition key column or a cluster key column - * + * * @see #isPartitionKeyColumn() * @see #isClusterKeyColumn() */ @@ -116,7 +117,7 @@ public interface CassandraPersistentProperty /** * Whether to force-quote the column names of this property. - * + * * @param forceQuote * @see CassandraPersistentProperty#getColumnNames() */ @@ -126,7 +127,7 @@ public interface CassandraPersistentProperty * If this property is mapped with a single column, set the column name to the given {@link CqlIdentifier}. If this * property is not mapped by a single column, throws {@link IllegalStateException}. If the given column name is null, * {@link IllegalArgumentException} is thrown. - * + * * @param columnName */ void setColumnName(CqlIdentifier columnName); @@ -134,18 +135,25 @@ public interface CassandraPersistentProperty /** * 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 null elements. - * + * * @param columnName */ void setColumnNames(List columnNames); - public enum PropertyToFieldNameConverter implements Converter { + /** + * Returns whether the property is a {@link java.util.Map}. + * + * @return a boolean indicating whether this property type is a {@link java.util.Map}. + */ + boolean isMapLike(); + + enum PropertyToFieldNameConverter implements Converter { INSTANCE; @Override - public String convert(CassandraPersistentProperty source) { - return source.getColumnName().toCql(); + public String convert(CassandraPersistentProperty property) { + return property.getColumnName().toCql(); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java index 4d251d232..a17984ed7 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java @@ -51,27 +51,28 @@ import com.datastax.driver.core.Row; * Base class for {@link RepositoryQuery} implementations for Cassandra. * * @author Mark Paluch + * @author John Blum */ public abstract class AbstractCassandraQuery implements RepositoryQuery { protected static Logger log = LoggerFactory.getLogger(AbstractCassandraQuery.class); - private final CassandraQueryMethod method; + private final CassandraQueryMethod queryMethod; private final CassandraOperations template; /** * Creates a new {@link AbstractCassandraQuery} from the given {@link CassandraQueryMethod} and * {@link CassandraOperations}. * - * @param method must not be {@literal null}. + * @param queryMethod must not be {@literal null}. * @param operations must not be {@literal null}. */ - public AbstractCassandraQuery(CassandraQueryMethod method, CassandraOperations operations) { + public AbstractCassandraQuery(CassandraQueryMethod queryMethod, CassandraOperations operations) { - Assert.notNull(method, "CassandraQueryMethod must not be null"); + Assert.notNull(queryMethod, "CassandraQueryMethod must not be null"); Assert.notNull(operations, "CassandraOperations must not be null"); - this.method = method; + this.queryMethod = queryMethod; this.template = operations; } @@ -80,7 +81,7 @@ public abstract class AbstractCassandraQuery implements RepositoryQuery { */ @Override public CassandraQueryMethod getQueryMethod() { - return method; + return queryMethod; } /* (non-Javadoc) @@ -89,22 +90,23 @@ public abstract class AbstractCassandraQuery implements RepositoryQuery { @Override public Object execute(Object[] parameters) { - CassandraParameterAccessor accessor = new ConvertingParameterAccessor(template.getConverter(), - new CassandraParametersParameterAccessor(method, parameters)); - String query = createQuery(accessor); + CassandraParameterAccessor parameterAccessor = new ConvertingParameterAccessor(template.getConverter(), + new CassandraParametersParameterAccessor(queryMethod, parameters)); - ResultProcessor processor = method.getResultProcessor().withDynamicProjection(accessor); + String query = createQuery(parameterAccessor); - CassandraQueryExecution cassandraQueryExecution = getExecution(query, accessor, - new ResultProcessingConverter(processor)); + ResultProcessor resultProcessor = queryMethod.getResultProcessor().withDynamicProjection(parameterAccessor); - CassandraReturnedType returnedType = new CassandraReturnedType(processor.getReturnedType(), template.getConverter().getCustomConversions()); + CassandraQueryExecution queryExecution = getExecution(query, parameterAccessor, + new ResultProcessingConverter(resultProcessor)); - if (returnedType.isProjecting()) { - return cassandraQueryExecution.execute(query, returnedType.getDomainType()); - } + CassandraReturnedType returnedType = new CassandraReturnedType(resultProcessor.getReturnedType(), + template.getConverter().getCustomConversions()); - return cassandraQueryExecution.execute(query, returnedType.getReturnedType()); + Class resultType = (returnedType.isProjecting() ? returnedType.getDomainType() + : returnedType.getReturnedType()); + + return queryExecution.execute(query, resultType); } /** @@ -123,11 +125,11 @@ public abstract class AbstractCassandraQuery implements RepositoryQuery { private CassandraQueryExecution getExecutionToWrap(CassandraParameterAccessor accessor, Converter resultProcessing) { - if (method.isCollectionQuery()) { + if (queryMethod.isCollectionQuery()) { return new CollectionExecution(template); - } else if (method.isResultSetQuery()) { + } else if (queryMethod.isResultSetQuery()) { return new ResultSetQuery(template); - } else if (method.isStreamQuery()) { + } else if (queryMethod.isStreamQuery()) { return new StreamExecution(template, resultProcessing); } else { return new SingleEntityExecution(template); @@ -145,7 +147,7 @@ public abstract class AbstractCassandraQuery implements RepositoryQuery { public Object getCollectionOfEntity(ResultSet resultSet, Class declaredReturnType, Class returnedUnwrappedObjectType) { - Collection results = null; + Collection results; if (ClassUtils.isAssignable(SortedSet.class, declaredReturnType)) { results = new TreeSet(); @@ -156,6 +158,7 @@ public abstract class AbstractCassandraQuery implements RepositoryQuery { } CassandraConverter converter = template.getConverter(); + for (Row row : resultSet) { results.add(converter.read(returnedUnwrappedObjectType, row)); } @@ -171,45 +174,51 @@ public abstract class AbstractCassandraQuery implements RepositoryQuery { */ @Deprecated public Object getSingleEntity(ResultSet resultSet, Class type) { - if (resultSet.isExhausted()) { - return null; + + Object result = (resultSet.isExhausted() ? null : template.getConverter().read(type, resultSet.one())); + + warnIfMoreResults(resultSet); + + return result; + } + + private void warnIfMoreResults(ResultSet resultSet) { + if (log.isWarnEnabled() && !resultSet.isExhausted()) { + int count = 0; + + while (resultSet.one() != null) { + count++; + } + + log.warn("ignoring extra {} row{}", count, count == 1 ? "" : "s"); } - - Iterator iterator = resultSet.iterator(); - Object object = template.getConverter().read(type, iterator.next()); - - warnIfMoreResults(iterator); - - return object; } @Deprecated protected void warnIfMoreResults(Iterator iterator) { if (log.isWarnEnabled() && iterator.hasNext()) { + int count = 0; - int i = 0; - while (iterator.hasNext()) { - iterator.next(); - i++; + for ( ; iterator.hasNext(); iterator.next()) { + count++; } - log.warn("ignoring extra {} row{}", i, i == 1 ? "" : "s"); + log.warn("ignoring extra {} row{}", count, count == 1 ? "" : "s"); } } - @Deprecated - public ConversionService getConversionService() { - return template.getConverter().getConversionService(); - } - /** - * @param conversionService * @deprecated {@link org.springframework.data.cassandra.mapping.CassandraMappingContext} handles type conversion. */ @Deprecated public void setConversionService(ConversionService conversionService) { throw new UnsupportedOperationException("setConversionService(ConversionService) is not supported anymore. " - + "Please use CassandraMappingContext instead"); + + "Please use CassandraMappingContext instead"); + } + + @Deprecated + public ConversionService getConversionService() { + return template.getConverter().getConversionService(); } /** @@ -229,37 +238,33 @@ public abstract class AbstractCassandraQuery implements RepositoryQuery { this.customConversions = customConversions; } - boolean isProjecting(){ + boolean isProjecting() { - if(!returnedType.isProjecting()){ + if (!returnedType.isProjecting()) { return false; } - // Spring Data Cassandra allows List and Map declarations on query methods - // so we don't want to let projection kick in - if(ClassUtils.isAssignable(Map.class, returnedType.getReturnedType())){ + // Spring Data Cassandra allows List and Map declarations + // on query methods so we don't want to let projection kick in + if (ClassUtils.isAssignable(Map.class, returnedType.getReturnedType())) { return false; } // Type conversion using registered conversions is handled on template level - if(customConversions.hasCustomWriteTarget(returnedType.getReturnedType())){ + if (customConversions.hasCustomWriteTarget(returnedType.getReturnedType())) { return false; } // Don't apply projection on Cassandra simple types - if(customConversions.isSimpleType(returnedType.getReturnedType())){ - return false; - } - - return true; - } - - Class getReturnedType() { - return returnedType.getReturnedType(); + return !customConversions.isSimpleType(returnedType.getReturnedType()); } Class getDomainType() { return returnedType.getDomainType(); } + + Class getReturnedType() { + return returnedType.getReturnedType(); + } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameters.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameters.java index dc9048711..7c780261e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameters.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameters.java @@ -19,13 +19,11 @@ import java.lang.reflect.Method; import java.util.List; import org.springframework.core.MethodParameter; -import org.springframework.data.cassandra.mapping.CassandraSimpleTypeHolder; import org.springframework.data.cassandra.mapping.CassandraType; import org.springframework.data.cassandra.repository.query.CassandraParameters.CassandraParameter; import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; - -import com.datastax.driver.core.DataType; +import org.springframework.util.Assert; /** * Custom extension of {@link Parameters} discovering additional properties of query method parameters. @@ -78,14 +76,11 @@ public class CassandraParameters extends Parameters getParameterType(int index) { - return getParameters().getParameter(index).getType(); - } - - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.repository.query.ParametersParameterAccessor#getParameters() */ @Override @@ -79,4 +71,12 @@ public class CassandraParametersParameterAccessor extends ParametersParameterAcc return (CassandraParameters) super.getParameters(); } + /* + * (non-Javadoc) + * @see org.springframework.data.cassandra.repository.query.CassandraParameterAccessor#getParameterType(int) + */ + @Override + public Class getParameterType(int index) { + return getParameters().getParameter(index).getType(); + } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreator.java index af5ef8e47..b3dc0f3cd 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreator.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.regex.Pattern; import org.slf4j.Logger; @@ -39,7 +38,6 @@ import org.springframework.data.repository.query.parser.Part; import org.springframework.data.repository.query.parser.Part.Type; import org.springframework.data.repository.query.parser.PartTree; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import com.datastax.driver.core.querybuilder.Clause; import com.datastax.driver.core.querybuilder.QueryBuilder; @@ -50,35 +48,39 @@ import com.datastax.driver.core.querybuilder.Select; * * @author Matthew Adams * @author Mark Paluch + * @author John Blum */ class CassandraQueryCreator extends AbstractQueryCreator { - private static final Pattern PUNCTATION_PATTERN = Pattern.compile("\\p{Punct}"); + private static final Pattern PUNCTUATION_PATTERN = Pattern.compile("\\p{Punct}"); private static final Logger LOG = LoggerFactory.getLogger(CassandraQueryCreator.class); - private final CassandraMappingContext context; - private final WhereBuilder whereBuilder = new WhereBuilder(); + + private final CassandraMappingContext mappingContext; + private final CassandraPersistentEntity entity; + private final WhereBuilder whereBuilder = new WhereBuilder(); + /** * Creates a new {@link CassandraQueryCreator} from the given {@link PartTree}, {@link ConvertingParameterAccessor} * and {@link MappingContext}. - * + * * @param tree must not be {@literal null}. * @param accessor must not be {@literal null}. - * @param context must not be {@literal null}. + * @param mappingContext must not be {@literal null}. * @param entityMetadata must not be {@literal null}. */ - public CassandraQueryCreator(PartTree tree, CassandraParameterAccessor accessor, CassandraMappingContext context, - EntityMetadata entityMetadata) { + public CassandraQueryCreator(PartTree tree, CassandraParameterAccessor accessor, + CassandraMappingContext mappingContext, EntityMetadata entityMetadata) { super(tree, accessor); - Assert.notNull(context, "CassandraMappingContext must not be null"); - Assert.notNull(entityMetadata, "EntityInformation must not be null"); + Assert.notNull(mappingContext, "CassandraMappingContext must not be null"); + Assert.notNull(entityMetadata, "EntityMetaData must not be null"); - this.context = context; - this.entity = context.getPersistentEntity(entityMetadata.getJavaType()); + this.mappingContext = mappingContext; + this.entity = mappingContext.getPersistentEntity(entityMetadata.getJavaType()); } /* (non-Javadoc) @@ -87,8 +89,9 @@ class CassandraQueryCreator extends AbstractQueryCreator { @Override protected Clause create(Part part, Iterator iterator) { - PersistentPropertyPath path = context.getPersistentPropertyPath(part.getProperty()); + PersistentPropertyPath path = mappingContext.getPersistentPropertyPath(part.getProperty()); CassandraPersistentProperty property = path.getLeafProperty(); + return from(part, property, (PotentiallyConvertingIterator) iterator); } @@ -103,18 +106,19 @@ class CassandraQueryCreator extends AbstractQueryCreator { } whereBuilder.and(base); + return create(part, iterator); } /* * Cassandra does not support OR queries. - * + * * (non-Javadoc) * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#or(java.lang.Object, java.lang.Object) */ @Override protected Clause or(Clause base, Clause criteria) { - throw new InvalidDataAccessApiUsageException(String.format("Cassandra does not support an OR operator!")); + throw new InvalidDataAccessApiUsageException("Cassandra does not support an OR operator"); } /* (non-Javadoc) @@ -166,14 +170,18 @@ class CassandraQueryCreator extends AbstractQueryCreator { case SIMPLE_PROPERTY: return QueryBuilder.eq(columnName(property), parameters.nextConverted(property)); default: - throw new InvalidDataAccessApiUsageException( - String.format("Unsupported Keyword: [%s] in part [%s]", type, part)); + throw new InvalidDataAccessApiUsageException(String.format( + "Unsupported keyword [%s] in part [%s]", type, part)); } } + private static String columnName(CassandraPersistentProperty property) { + return property.getColumnName().toCql(); + } + private Clause containing(CassandraPersistentProperty property, Object bindableValue) { - if (property.isCollectionLike() || ClassUtils.isAssignable(Map.class, property.getType())) { + if (property.isCollectionLike() || property.isMapLike()) { return QueryBuilder.contains(columnName(property), bindableValue); } @@ -182,32 +190,22 @@ class CassandraQueryCreator extends AbstractQueryCreator { private Object like(Type type, Object value) { - if (value == null) { - return null; + if (value != null) { + switch (type) { + case LIKE: + return value; + case CONTAINING: + return "%" + value + "%"; + case STARTING_WITH: + return value + "%"; + case ENDING_WITH: + return "%" + value; + } + + throw new IllegalArgumentException(String.format("Part Type [%s] not supported with like queries", type)); } - if (type == Type.LIKE) { - return value; - } - - if (type == Type.CONTAINING) { - return "%" + value + "%"; - } - - if (type == Type.STARTING_WITH) { - return value + "%"; - } - - if (type == Type.ENDING_WITH) { - return "%" + value; - } - - throw new IllegalArgumentException(String.format("Part Type [%s] not supported with like queries", type)); - - } - - private static String columnName(CassandraPersistentProperty property) { - return property.getColumnName().toCql(); + return null; } private Object[] nextAsArray(CassandraPersistentProperty property, PotentiallyConvertingIterator iterator) { @@ -225,7 +223,7 @@ class CassandraQueryCreator extends AbstractQueryCreator { /** * Where clause builder. Collects {@link Clause clauses} and builds the where-clause depending on the WHERE type. - * + * * @author Mark Paluch */ static class WhereBuilder { @@ -233,16 +231,15 @@ class CassandraQueryCreator extends AbstractQueryCreator { private List clauses = new ArrayList(); Clause and(Clause clause) { - clauses.add(clause); return clause; } Select.Where build(Select.Where where) { - for (Clause clause : clauses) { where = where.and(clause); } + return where; } } @@ -255,19 +252,14 @@ class CassandraQueryCreator extends AbstractQueryCreator { /** * Build a {@link Select} statement from the given {@link WhereBuilder} and {@link Sort}. Resolves property names * for {@link Sort} using the {@link CassandraPersistentEntity}. - * - * @param whereBuilder - * @param entity - * @param sort - * @return */ static Select select(CassandraPersistentEntity entity, WhereBuilder whereBuilder, Sort sort) { Select select = QueryBuilder.select().from(entity.getTableName().toCql()); + whereBuilder.build(select.where()); if (sort != null) { - for (Order order : sort) { String dotPath = order.getProperty(); @@ -287,7 +279,7 @@ class CassandraQueryCreator extends AbstractQueryCreator { private static CassandraPersistentProperty getPersistentProperty(CassandraPersistentEntity entity, String dotPath) { - String[] segments = PUNCTATION_PATTERN.split(dotPath); + String[] segments = PUNCTUATION_PATTERN.split(dotPath); CassandraPersistentProperty property = null; CassandraPersistentEntity currentEntity = entity; @@ -301,12 +293,11 @@ class CassandraQueryCreator extends AbstractQueryCreator { } if (property != null) { - return property; } - throw new IllegalArgumentException( - String.format("Cannot resolve path [%s] to a property of [%s]", dotPath, entity.getName())); + throw new IllegalArgumentException(String.format( + "Cannot resolve path [%s] to a property of [%s]", dotPath, entity.getName())); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethod.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethod.java index b38f07a57..ec47468d6 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethod.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethod.java @@ -40,29 +40,32 @@ import com.datastax.driver.core.ResultSet; * @author Matthew Adams * @author Oliver Gierke * @author Mark Paluch + * @author John Blum */ public class CassandraQueryMethod extends QueryMethod { - private final Method method; + private CassandraEntityMetadata entityMetadata; + private final CassandraMappingContext mappingContext; - private CassandraEntityMetadata metadata; + + private final Method method; /** * Creates a new {@link CassandraQueryMethod} from the given {@link Method}. * * @param method must not be {@literal null}. - * @param metadata must not be {@literal null}. + * @param repositoryMetadata must not be {@literal null}. * @param projectionFactory must not be {@literal null}. * @param mappingContext must not be {@literal null}. */ - public CassandraQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory, - CassandraMappingContext mappingContext) { + public CassandraQueryMethod(Method method, RepositoryMetadata repositoryMetadata, + ProjectionFactory projectionFactory, CassandraMappingContext mappingContext) { - super(method, metadata, factory); + super(method, repositoryMetadata, projectionFactory); Assert.notNull(mappingContext, "MappingContext must not be null"); - verify(method, metadata); + verify(method, repositoryMetadata); this.method = method; this.mappingContext = mappingContext; @@ -81,33 +84,34 @@ public class CassandraQueryMethod extends QueryMethod { } @Override + @SuppressWarnings("unchecked") public CassandraEntityMetadata getEntityInformation() { - if (metadata == null) { - + if (entityMetadata == null) { Class returnedObjectType = getReturnedObjectType(); Class domainClass = getDomainClass(); if (ClassUtils.isPrimitiveOrWrapper(returnedObjectType)) { - - this.metadata = new SimpleCassandraEntityMetadata((Class) domainClass, - mappingContext.getPersistentEntity(domainClass)); + this.entityMetadata = new SimpleCassandraEntityMetadata((Class) domainClass, + mappingContext.getPersistentEntity(domainClass)); } else { - CassandraPersistentEntity returnedEntity = mappingContext.getPersistentEntity(returnedObjectType); CassandraPersistentEntity managedEntity = mappingContext.getPersistentEntity(domainClass); - returnedEntity = returnedEntity == null || returnedEntity.getType().isInterface() ? managedEntity - : returnedEntity; - CassandraPersistentEntity collectionEntity = domainClass.isAssignableFrom(returnedObjectType) - ? returnedEntity : managedEntity; - this.metadata = new SimpleCassandraEntityMetadata((Class) returnedEntity.getType(), - collectionEntity); + returnedEntity = (returnedEntity == null || returnedEntity.getType().isInterface() + ? managedEntity : returnedEntity); + + // TODO collectionEntity? + CassandraPersistentEntity collectionEntity = domainClass.isAssignableFrom(returnedObjectType) + ? returnedEntity : managedEntity; + + this.entityMetadata = new SimpleCassandraEntityMetadata( + (Class) returnedEntity.getType(), collectionEntity); } } - return this.metadata; + return this.entityMetadata; } /* (non-Javadoc) @@ -132,9 +136,8 @@ public class CassandraQueryMethod extends QueryMethod { * @return */ public String getAnnotatedQuery() { - String query = (String) AnnotationUtils.getValue(getQueryAnnotation()); - return StringUtils.hasText(query) ? query : null; + return (StringUtils.hasText(query) ? query : null); } /** diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessor.java index a288019e5..b9d87a1cf 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessor.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessor.java @@ -52,7 +52,6 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { private final CassandraParameterAccessor delegate; ConvertingParameterAccessor(CassandraConverter cassandraConverter, CassandraParameterAccessor delegate) { - this.cassandraConverter = cassandraConverter; this.delegate = delegate; } @@ -102,11 +101,8 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { DataType dataType = delegate.getDataType(index); - if (dataType != null) { - return dataType; - } - - return cassandraConverter.getMappingContext().getDataType(getParameterType(index)); + return (dataType != null ? dataType + : cassandraConverter.getMappingContext().getDataType(getParameterType(index))); } /* (non-Javadoc) @@ -150,13 +146,14 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { && property.isCollectionLike()) { Class customWriteTarget = getCustomConversions().getCustomWriteTarget(property.getActualType()); + if (Collection.class.isAssignableFrom(property.getType()) && bindableValue instanceof Collection) { Collection original = (Collection) bindableValue; Collection converted = CollectionFactory.createCollection(property.getType(), original.size()); - for (Object o : original) { - converted.add(getConversionService().convert(o, customWriteTarget)); + for (Object element : original) { + converted.add(getConversionService().convert(element, customWriteTarget)); } return converted; @@ -181,12 +178,12 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { /** * Return the {@link DataType} based on annotated parameters with {@link CassandraType}, the * {@link CassandraPersistentProperty} type or the declared parameter type. - * - * @param index - * @param cassandraPersistentProperty + * + * @param index index of parameter. + * @param property {@link CassandraPersistentProperty}. * @return the {@link DataType} */ - DataType getDataType(int index, CassandraPersistentProperty cassandraPersistentProperty) { + DataType getDataType(int index, CassandraPersistentProperty property) { CassandraType cassandraType = delegate.findCassandraType(index); @@ -197,24 +194,24 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { CassandraMappingContext mappingContext = cassandraConverter.getMappingContext(); TypeInformation typeInformation = ClassTypeInformation.from(getParameterType(index)); - if (cassandraPersistentProperty == null) { + if (property == null) { return mappingContext.getDataType(typeInformation.getType()); } - DataType dataType = mappingContext.getDataType(cassandraPersistentProperty); + DataType dataType = mappingContext.getDataType(property); - if (cassandraPersistentProperty.isCollectionLike() && !typeInformation.isCollectionLike()) { + if (property.isCollectionLike() && !typeInformation.isCollectionLike()) { if (dataType instanceof CollectionType) { - CollectionType collectionType = (CollectionType) dataType; + if (collectionType.getTypeArguments().size() == 1) { return collectionType.getTypeArguments().get(0); } } } - if (!cassandraPersistentProperty.isCollectionLike() && typeInformation.isCollectionLike()) { + if (!property.isCollectionLike() && typeInformation.isCollectionLike()) { if (typeInformation.isAssignableFrom(SET)) { return DataType.set(dataType); @@ -223,18 +220,18 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { return DataType.list(dataType); } - if (cassandraPersistentProperty.isMap()) { + if (property.isMap()) { if (dataType instanceof CollectionType) { - CollectionType collectionType = (CollectionType) dataType; + if (collectionType.getTypeArguments().size() == 2) { return collectionType.getTypeArguments().get(0); } } } - return mappingContext.getDataType(cassandraPersistentProperty); + return mappingContext.getDataType(property); } /** @@ -299,5 +296,6 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { * @return the converted object, may be {@literal null}. */ Object nextConverted(CassandraPersistentProperty property); + } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQuery.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQuery.java index f1106a52d..a8a5731dc 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQuery.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQuery.java @@ -24,32 +24,33 @@ import org.springframework.data.repository.query.parser.PartTree; /** * {@link RepositoryQuery} implementation for Cassandra. - * + * * @author Matthew Adams * @author Mark Paluch */ public class PartTreeCassandraQuery extends AbstractCassandraQuery { + private final CassandraMappingContext mappingContext; + private final PartTree tree; - private final CassandraMappingContext context; /** * Creates a new {@link PartTreeCassandraQuery} from the given {@link QueryMethod} and {@link CassandraTemplate}. - * - * @param method must not be {@literal null}. + * + * @param queryMethod must not be {@literal null}. * @param operations must not be {@literal null}. */ - public PartTreeCassandraQuery(CassandraQueryMethod method, CassandraOperations operations) { + public PartTreeCassandraQuery(CassandraQueryMethod queryMethod, CassandraOperations operations) { - super(method, operations); + super(queryMethod, operations); - this.tree = new PartTree(method.getName(), method.getEntityInformation().getJavaType()); - this.context = operations.getConverter().getMappingContext(); + this.tree = new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType()); + this.mappingContext = operations.getConverter().getMappingContext(); } /** * Return the {@link PartTree} backing the query. - * + * * @return the tree */ public PartTree getTree() { @@ -61,10 +62,11 @@ public class PartTreeCassandraQuery extends AbstractCassandraQuery { * @see org.springframework.data.cassandra.repository.query.AbstractCassandraQuery#createQuery(org.springframework.data.cassandra.repository.query.CassandraParameterAccessor, boolean) */ @Override - protected String createQuery(CassandraParameterAccessor accessor) { + protected String createQuery(CassandraParameterAccessor parameterAccessor) { - CassandraQueryCreator creator = new CassandraQueryCreator(tree, accessor, context, + CassandraQueryCreator queryCreator = new CassandraQueryCreator(tree, parameterAccessor, mappingContext, getQueryMethod().getEntityInformation()); - return creator.createQuery().toString(); + + return queryCreator.createQuery().toString(); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/SimpleCassandraEntityMetadata.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/SimpleCassandraEntityMetadata.java index 906714590..3abe092c3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/SimpleCassandraEntityMetadata.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/SimpleCassandraEntityMetadata.java @@ -21,29 +21,30 @@ import org.springframework.util.Assert; /** * Implementation of {@link CassandraEntityMetadata} based on the type and {@link CassandraPersistentEntity}. - * + * * @author Mark Paluch * @since 1.5 */ class SimpleCassandraEntityMetadata implements CassandraEntityMetadata { + private final CassandraPersistentEntity entity; + private final Class type; - private final CassandraPersistentEntity tableEntity; /** * Creates a new {@link SimpleCassandraEntityMetadata} using the given type and {@link CassandraPersistentEntity} to * use for table lookups. * * @param type must not be {@literal null}. - * @param tableEntity must not be {@literal null} or empty. + * @param entity must not be {@literal null} or empty. */ - public SimpleCassandraEntityMetadata(Class type, CassandraPersistentEntity tableEntity) { + public SimpleCassandraEntityMetadata(Class type, CassandraPersistentEntity entity) { - Assert.notNull(type, "Type must not be null!"); - Assert.notNull(tableEntity, "Collection entity must not be null or empty!"); + Assert.notNull(type, "Type must not be null"); + Assert.notNull(entity, "Collection entity must not be null or empty"); this.type = type; - this.tableEntity = tableEntity; + this.entity = entity; } /* (non-Javadoc) @@ -51,7 +52,7 @@ class SimpleCassandraEntityMetadata implements CassandraEntityMetadata { */ @Override public CqlIdentifier getTableName() { - return tableEntity.getTableName(); + return entity.getTableName(); } /* (non-Javadoc) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactory.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactory.java index bf9a7e538..14d92e071 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactory.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactory.java @@ -1,12 +1,12 @@ /* * Copyright 2013-2016 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. @@ -32,6 +32,7 @@ import org.springframework.data.repository.core.NamedQueries; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.RepositoryFactorySupport; +import org.springframework.data.repository.query.EvaluationContextProvider; import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.repository.query.QueryLookupStrategy.Key; import org.springframework.data.repository.query.RepositoryQuery; @@ -39,11 +40,12 @@ import org.springframework.util.Assert; /** * Factory to create {@link TypedIdCassandraRepository} instances. - * + * * @author Alex Shvid * @author Matthew T. Adams * @author Thomas Darimont * @author Mark Paluch + * @author John Blum */ public class CassandraRepositoryFactory extends RepositoryFactorySupport { @@ -52,7 +54,7 @@ public class CassandraRepositoryFactory extends RepositoryFactorySupport { /** * Creates a new {@link CassandraRepositoryFactory} with the given {@link CassandraOperations}. - * + * * @param cassandraOperations must not be {@literal null} */ public CassandraRepositoryFactory(CassandraOperations cassandraOperations) { @@ -63,7 +65,8 @@ public class CassandraRepositoryFactory extends RepositoryFactorySupport { this.mappingContext = cassandraOperations.getConverter().getMappingContext(); } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryBaseClass(org.springframework.data.repository.core.RepositoryMetadata) */ @Override @@ -71,7 +74,8 @@ public class CassandraRepositoryFactory extends RepositoryFactorySupport { return SimpleCassandraRepository.class; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryInformation) */ @Override @@ -81,7 +85,8 @@ public class CassandraRepositoryFactory extends RepositoryFactorySupport { return getTargetRepositoryViaReflection(information, entityInformation, cassandraOperations); } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class) */ @Override @@ -99,17 +104,27 @@ public class CassandraRepositoryFactory extends RepositoryFactorySupport { cassandraOperations.getConverter()); } - /* (non-Javadoc) - * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key) + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(Key) */ @Override protected QueryLookupStrategy getQueryLookupStrategy(Key key) { + return getQueryLookupStrategy(key, null); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(Key, EvaluationContextProvider) + */ + @Override + protected QueryLookupStrategy getQueryLookupStrategy(Key key, EvaluationContextProvider evaluationContextProvider) { return new CassandraQueryLookupStrategy(); } private class CassandraQueryLookupStrategy implements QueryLookupStrategy { - /* + /* * (non-Javadoc) * @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries) */ diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryBean.java index c1ee13cd5..100295a87 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryBean.java @@ -1,12 +1,12 @@ /* * Copyright 2013-2014 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. @@ -26,11 +26,15 @@ import org.springframework.util.Assert; /** * {@link org.springframework.beans.factory.FactoryBean} to create {@link TypedIdCassandraRepository} instances. - * + * * @author Alex Shvid + * @author John Blum + * @see java.io.Serializable + * @see org.springframework.data.repository.Repository + * @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport */ -public class CassandraRepositoryFactoryBean, S, ID extends Serializable> extends - RepositoryFactoryBeanSupport { +public class CassandraRepositoryFactoryBean, S, ID extends Serializable> + extends RepositoryFactoryBeanSupport { private CassandraTemplate cassandraTemplate; @@ -40,9 +44,10 @@ public class CassandraRepositoryFactoryBean, S, ID e } /** - * Configures the {@link CassandraTemplate} to be used. - * - * @param operations the operations to set + * Configures the {@link CassandraTemplate} used for Cassandra data access operations. + * + * @param cassandraTemplate {@link CassandraTemplate} used to perform CRUD, Query and general data access operations + * on Apache Cassandra. */ public void setCassandraTemplate(CassandraTemplate cassandraTemplate) { this.cassandraTemplate = cassandraTemplate; @@ -51,7 +56,7 @@ public class CassandraRepositoryFactoryBean, S, ID e /* * (non-Javadoc) - * + * * @see * org.springframework.data.repository.support.RepositoryFactoryBeanSupport * #afterPropertiesSet() @@ -59,7 +64,6 @@ public class CassandraRepositoryFactoryBean, S, ID e @Override public void afterPropertiesSet() { super.afterPropertiesSet(); - Assert.notNull(cassandraTemplate, "cassandraTemplate must not be null!"); + Assert.notNull(cassandraTemplate, "CassandraTemplate must not be null!"); } - } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraParametersUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraParametersUnitTests.java index aea5da220..4db31957d 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraParametersUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraParametersUnitTests.java @@ -27,7 +27,6 @@ import org.mockito.runners.MockitoJUnitRunner; import org.springframework.data.cassandra.domain.Person; import org.springframework.data.cassandra.mapping.CassandraType; -import com.datastax.driver.core.DataType; import com.datastax.driver.core.DataType.Name; /** @@ -44,7 +43,7 @@ public class CassandraParametersUnitTests { * @see DATACASS-296 */ @Test - public void shouldUnknownDataTypeForSimpleType() throws Exception { + public void shouldReturnUnknownDataTypeForSimpleType() throws Exception { Method method = PersonRepository.class.getMethod("findByFirstname", String.class); CassandraParameters cassandraParameters = new CassandraParameters(method); 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 906f7a4ce..cf6fb8c43 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 @@ -47,26 +47,25 @@ import org.springframework.data.repository.query.parser.PartTree; /** * Unit tests for {@link CassandraQueryCreator}. - * + * * @author Mark Paluch - * @soundtrack Odyssey - Everybody Move 9Club Mix */ public class CassandraQueryCreatorUnitTests { CassandraMappingContext context; CassandraConverter converter; - @Rule public ExpectedException expection = ExpectedException.none(); + @Rule + public ExpectedException exception = ExpectedException.none(); @Before public void setUp() throws SecurityException, NoSuchMethodException { - context = new BasicCassandraMappingContext(); converter = new MappingCassandraConverter(context); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsQueryCorrectly() { @@ -77,7 +76,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsQueryWithSortCorrectly() { @@ -88,7 +87,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsAndQueryCorrectly() { @@ -99,15 +98,15 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test(expected = InvalidDataAccessApiUsageException.class) - public void rejectsNegatingQueryQuery() { + public void rejectsNegatingQuery() { createQuery("findByFirstnameNot", Person.class, "Walter"); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test(expected = InvalidDataAccessApiUsageException.class) public void rejectsOrQuery() { @@ -115,7 +114,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsGreaterThanQueryCorrectly() { @@ -126,7 +125,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsGreaterThanEqualQueryCorrectly() { @@ -137,7 +136,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsLessThanQueryCorrectly() { @@ -148,7 +147,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsLessThanEqualQueryCorrectly() { @@ -159,7 +158,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsInQueryCorrectly() { @@ -170,7 +169,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsInQueryWithListCorrectly() { @@ -181,30 +180,32 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsInQueryWithArrayCorrectly() { - String query = createQuery("findByFirstnameInAndLastname", Person.class, new String[] { "Walter", "Gus" }, "Fring"); + String query = createQuery("findByFirstnameInAndLastname", Person.class, + new String[] { "Walter", "Gus" }, "Fring"); assertThat(query, is(equalTo("SELECT * FROM person WHERE firstname IN ('Walter','Gus') AND lastname='Fring';"))); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsLikeQueryCorrectly() { assertThat(createQuery("findByFirstnameLike", Person.class, "Wal%ter"), is(equalTo("SELECT * FROM person WHERE firstname LIKE 'Wal%ter';"))); + assertThat(createQuery("findByFirstnameLike", Person.class, "Walter"), is(equalTo("SELECT * FROM person WHERE firstname LIKE 'Walter';"))); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsStartsWithQueryCorrectly() { @@ -215,7 +216,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsEndsWithQueryCorrectly() { @@ -226,7 +227,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsContainsQueryOnSimplePropertyCorrectly() { @@ -237,7 +238,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsContainsQueryOnSetPropertyCorrectly() { @@ -248,7 +249,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsContainsQueryOnListPropertyCorrectly() { @@ -259,7 +260,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsContainsQueryOnMapPropertyCorrectly() { @@ -270,7 +271,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsIsTrueQueryCorrectly() { @@ -281,7 +282,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsIsFalseQueryCorrectly() { @@ -292,7 +293,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsQueryUsingQuotingCorrectly() { @@ -303,7 +304,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsFindByPrimaryKeyPartCorrectly() { @@ -314,7 +315,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsFindByPrimaryKeyPartWithSortCorrectly() { @@ -325,7 +326,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void createsFindByPrimaryKeyPartOfPrimaryKeyClassCorrectly() { @@ -337,7 +338,7 @@ public class CassandraQueryCreatorUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test(expected = IllegalStateException.class) public void createsFindByPrimaryKey2PartCorrectly() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethodUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethodUnitTests.java index 1378bbc26..56869b291 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethodUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethodUnitTests.java @@ -33,7 +33,7 @@ import org.springframework.data.repository.core.support.DefaultRepositoryMetadat /** * Unit tests for {@link CassandraQueryMethod}. - * + * * @author Mark Paluch */ public class CassandraQueryMethodUnitTests { @@ -46,7 +46,7 @@ public class CassandraQueryMethodUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void detectsCollectionFromRepoTypeIfReturnTypeNotAssignable() throws Exception { @@ -59,7 +59,7 @@ public class CassandraQueryMethodUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test(expected = IllegalArgumentException.class) public void rejectsNullMappingContext() throws Exception { @@ -71,7 +71,7 @@ public class CassandraQueryMethodUnitTests { } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void considersMethodAsCollectionQuery() throws Exception { @@ -88,8 +88,10 @@ public class CassandraQueryMethodUnitTests { return new CassandraQueryMethod(method, new DefaultRepositoryMetadata(repository), factory, context); } + @SuppressWarnings("unused") interface SampleRepository extends Repository { List method(); + } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessorUnitTests.java index d4c0c1940..ac3d2c7cb 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessorUnitTests.java @@ -20,7 +20,6 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; import java.time.LocalDate; -import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -40,127 +39,127 @@ import com.datastax.driver.core.DataType; /** * Unit tests for {@link ConvertingParameterAccessor}. - * + * * @author Mark Paluch */ @SuppressWarnings("Since15") @RunWith(MockitoJUnitRunner.class) public class ConvertingParameterAccessorUnitTests { - @Mock CassandraParameterAccessor delegateMock; - @Mock CassandraPersistentProperty propertyMock; + @Mock + private CassandraParameterAccessor mockParameterAccessor; + + @Mock + private CassandraPersistentProperty mockProperty; + + ConvertingParameterAccessor convertingParameterAccessor; + MappingCassandraConverter converter; - ConvertingParameterAccessor accessor; @Before public void setUp() { - this.converter = new MappingCassandraConverter(new BasicCassandraMappingContext()); this.converter.afterPropertiesSet(); - this.accessor = new ConvertingParameterAccessor(converter, delegateMock); + this.convertingParameterAccessor = new ConvertingParameterAccessor(converter, mockParameterAccessor); } /** - * @see DATACASS-296 + * @see DATACASS-296 */ @Test public void shouldReturnNullBindableValue() { - assertThat(accessor.getBindableValue(0), is(nullValue())); + assertThat(convertingParameterAccessor.getBindableValue(0), is(nullValue())); } /** - * @see DATACASS-296 + * @see DATACASS-296 */ @Test @SuppressWarnings({"rawtypes", "unchecked"}) public void shouldReturnNativeBindableValue() { + when(mockParameterAccessor.getBindableValue(0)).thenReturn("hello"); + when(mockParameterAccessor.getDataType(0)).thenReturn(DataType.varchar()); + when(mockParameterAccessor.getParameterType(0)).thenReturn((Class) String.class); - when(delegateMock.getBindableValue(0)).thenReturn("hello"); - when(delegateMock.getDataType(0)).thenReturn(DataType.varchar()); - when(delegateMock.getParameterType(0)).thenReturn((Class) String.class); - - assertThat(accessor.getBindableValue(0), is(equalTo((Object) "hello"))); + assertThat(convertingParameterAccessor.getBindableValue(0), is(equalTo((Object) "hello"))); } /** - * @see DATACASS-296 + * @see DATACASS-296 */ @Test @SuppressWarnings({"rawtypes", "unchecked"}) public void shouldReturnConvertedBindableValue() { - LocalDate localDate = LocalDate.of(2010, 7, 4); - when(delegateMock.getBindableValue(0)).thenReturn(localDate); - when(delegateMock.getParameterType(0)).thenReturn((Class) LocalDate.class); + when(mockParameterAccessor.getBindableValue(0)).thenReturn(localDate); + when(mockParameterAccessor.getParameterType(0)).thenReturn((Class) LocalDate.class); - assertThat(accessor.getBindableValue(0), - is(equalTo((Object) com.datastax.driver.core.LocalDate.fromYearMonthDay(2010, 7, 4)))); + assertThat(convertingParameterAccessor.getBindableValue(0), + is(equalTo((Object) com.datastax.driver.core.LocalDate.fromYearMonthDay(2010, 7, 4)))); } /** - * @see DATACASS-296 - * @see DATACASS-7 + * @see DATACASS-296 + * @see DATACASS-7 */ @Test public void shouldReturnDataTypeProvidedByDelegate() { + when(mockParameterAccessor.getDataType(0)).thenReturn(DataType.varchar()); - when(delegateMock.getDataType(0)).thenReturn(DataType.varchar()); - - assertThat(accessor.getDataType(0), is(equalTo(DataType.varchar()))); + assertThat(convertingParameterAccessor.getDataType(0), is(equalTo(DataType.varchar()))); } /** - * @see DATACASS-296 - * @see DATACASS-7 + * @see DATACASS-296 + * @see DATACASS-7 */ @Test @SuppressWarnings({"rawtypes", "unchecked"}) public void shouldConvertCollections() { - LocalDate localDate = LocalDate.of(2010, 7, 4); - when(delegateMock.iterator()).thenReturn((Iterator) Arrays.asList(Collections.singletonList(localDate)).iterator()); - when(delegateMock.getDataType(0)).thenReturn(DataType.list(DataType.date())); - when(delegateMock.getParameterType(0)).thenReturn((Class) List.class); - when(propertyMock.getType()).thenReturn((Class) List.class); - when(propertyMock.getActualType()).thenReturn((Class) LocalDate.class); - when(propertyMock.isCollectionLike()).thenReturn(true); + when(mockParameterAccessor.iterator()).thenReturn((Iterator) + Collections.singletonList(Collections.singletonList(localDate)).iterator()); + when(mockParameterAccessor.getDataType(0)).thenReturn(DataType.list(DataType.date())); + when(mockParameterAccessor.getParameterType(0)).thenReturn((Class) List.class); + when(mockProperty.getType()).thenReturn((Class) List.class); + when(mockProperty.getActualType()).thenReturn((Class) LocalDate.class); + when(mockProperty.isCollectionLike()).thenReturn(true); - PotentiallyConvertingIterator iterator = (PotentiallyConvertingIterator) accessor.iterator(); - Object converted = iterator.nextConverted(propertyMock); + PotentiallyConvertingIterator iterator = (PotentiallyConvertingIterator) convertingParameterAccessor.iterator(); + Object converted = iterator.nextConverted(mockProperty); assertThat(converted, is(instanceOf(List.class))); List list = (List) converted; + assertThat(list.get(0), is(instanceOf(com.datastax.driver.core.LocalDate.class))); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test @SuppressWarnings({"rawtypes", "unchecked"}) public void shouldProvideTypeBasedOnValue() { + when(mockParameterAccessor.getDataType(0)).thenReturn(null); + when(mockParameterAccessor.getParameterType(0)).thenReturn((Class) LocalDate.class); - when(delegateMock.getDataType(0)).thenReturn(null); - when(delegateMock.getParameterType(0)).thenReturn((Class) LocalDate.class); - - assertThat(accessor.getDataType(0), is(equalTo(DataType.date()))); + assertThat(convertingParameterAccessor.getDataType(0), is(equalTo(DataType.date()))); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "rawtypes", "unchecked" }) public void shouldProvideTypeBasedOnPropertyType() { + when(mockProperty.getDataType()).thenReturn(DataType.varchar()); + when(mockProperty.findAnnotation(CassandraType.class)).thenReturn(mock(CassandraType.class)); + when(mockParameterAccessor.getParameterType(0)).thenReturn((Class) String.class); + when(mockParameterAccessor.getDataType(0)).thenReturn(null); - when(propertyMock.getDataType()).thenReturn(DataType.varchar()); - when(propertyMock.findAnnotation(CassandraType.class)).thenReturn(mock(CassandraType.class)); - when(delegateMock.getParameterType(0)).thenReturn((Class) String.class); - when(delegateMock.getDataType(0)).thenReturn(null); - - assertThat(accessor.getDataType(0, propertyMock), is(equalTo(DataType.varchar()))); + assertThat(convertingParameterAccessor.getDataType(0, mockProperty), is(equalTo(DataType.varchar()))); } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQueryUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQueryUnitTests.java index 2bd5fc542..84c5fc33c 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQueryUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQueryUnitTests.java @@ -16,8 +16,8 @@ package org.springframework.data.cassandra.repository.query; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; import java.lang.reflect.Method; @@ -42,66 +42,64 @@ import org.springframework.data.repository.core.support.DefaultRepositoryMetadat /** * Unit tests for {@link PartTreeCassandraQuery}. - * + * * @author Mark Paluch */ @RunWith(MockitoJUnitRunner.class) public class PartTreeCassandraQueryUnitTests { - public @Rule ExpectedException exception = ExpectedException.none(); + @Rule + public ExpectedException exception = ExpectedException.none(); - @Mock CassandraOperations cassandraOperationsMock; + @Mock + private CassandraOperations mockCassandraOperations; - CassandraMappingContext mappingContext; - CassandraConverter converter; + private CassandraMappingContext mappingContext; + private CassandraConverter converter; @Before public void setUp() { - mappingContext = new BasicCassandraMappingContext(); converter = new MappingCassandraConverter(mappingContext); - when(cassandraOperationsMock.getConverter()).thenReturn(converter); + + when(mockCassandraOperations.getConverter()).thenReturn(converter); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldDeriveSimpleQuery() { - String query = deriveQueryFromMethod("findByLastname", "foo"); assertThat(query, is(equalTo("SELECT * FROM person WHERE lastname='foo';"))); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldDeriveSimpleQueryWithoutNames() { - String query = deriveQueryFromMethod("findPersonBy"); assertThat(query, is(equalTo("SELECT * FROM person;"))); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldDeriveAndQuery() { - String query = deriveQueryFromMethod("findByFirstnameAndLastname", "foo", "bar" ); assertThat(query, is(equalTo("SELECT * FROM person WHERE firstname='foo' AND lastname='bar';"))); } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void usesDynamicProjection() { - String query = deriveQueryFromMethod("findDynamicallyProjectedBy", PersonProjection.class); assertThat(query, is(equalTo("SELECT * FROM person;"))); @@ -109,7 +107,6 @@ public class PartTreeCassandraQueryUnitTests { private String deriveQueryFromMethod(String method, Object... args) { - Class[] types = new Class[args.length]; for (int i = 0; i < args.length; i++) { @@ -119,19 +116,18 @@ public class PartTreeCassandraQueryUnitTests { PartTreeCassandraQuery partTreeQuery = createQueryForMethod(method, types); CassandraParameterAccessor accessor = new CassandraParametersParameterAccessor(partTreeQuery.getQueryMethod(), args); - return partTreeQuery.createQuery(new ConvertingParameterAccessor(cassandraOperationsMock.getConverter(), accessor)); + + return partTreeQuery.createQuery(new ConvertingParameterAccessor(mockCassandraOperations.getConverter(), accessor)); } private PartTreeCassandraQuery createQueryForMethod(String methodName, Class... paramTypes) { - try { - Method method = Repo.class.getMethod(methodName, paramTypes); ProjectionFactory factory = new SpelAwareProxyProjectionFactory(); - CassandraQueryMethod queryMethod = new CassandraQueryMethod(method, new DefaultRepositoryMetadata(Repo.class), factory, - mappingContext); + CassandraQueryMethod queryMethod = new CassandraQueryMethod(method, + new DefaultRepositoryMetadata(Repo.class), factory, mappingContext); - return new PartTreeCassandraQuery(queryMethod, cassandraOperationsMock); + return new PartTreeCassandraQuery(queryMethod, mockCassandraOperations); } catch (NoSuchMethodException e) { throw new IllegalArgumentException(e.getMessage(), e); } catch (SecurityException e) { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryUnitTests.java index 29842dc2e..78c2db9e0 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryUnitTests.java @@ -36,21 +36,27 @@ import org.springframework.data.repository.Repository; /** * Unit tests for {@link CassandraRepositoryFactory}. - * + * * @author Mark Paluch */ @RunWith(MockitoJUnitRunner.class) @SuppressWarnings({ "rawtypes", "unchecked" }) public class CassandraRepositoryFactoryUnitTests { - @Mock CassandraTemplate template; - @Mock CassandraConverter converter; - @Mock CassandraMappingContext mappingContext; - @Mock CassandraPersistentEntity entity; + @Mock + private CassandraConverter converter; + + @Mock + private CassandraMappingContext mappingContext; + + @Mock + private CassandraPersistentEntity entity; + + @Mock + private CassandraTemplate template; @Before public void setUp() { - when(template.getConverter()).thenReturn(converter); when(converter.getMappingContext()).thenReturn(mappingContext); } @@ -60,12 +66,14 @@ public class CassandraRepositoryFactoryUnitTests { */ @Test public void usesMappingCassandraEntityInformationIfMappingContextSet() { - when(mappingContext.getPersistentEntity(Person.class)).thenReturn(entity); when(entity.getType()).thenReturn(Person.class); - CassandraRepositoryFactory factory = new CassandraRepositoryFactory(template); - CassandraEntityInformation entityInformation = factory.getEntityInformation(Person.class); + CassandraRepositoryFactory repositoryFactory = new CassandraRepositoryFactory(template); + + CassandraEntityInformation entityInformation = + repositoryFactory.getEntityInformation(Person.class); + assertTrue(entityInformation instanceof MappingCassandraEntityInformation); } @@ -74,16 +82,15 @@ public class CassandraRepositoryFactoryUnitTests { */ @Test public void createsRepositoryWithIdTypeLong() { - when(mappingContext.getPersistentEntity(Person.class)).thenReturn(entity); when(entity.getType()).thenReturn(Person.class); - CassandraRepositoryFactory factory = new CassandraRepositoryFactory(template); - MyPersonRepository repository = factory.getRepository(MyPersonRepository.class); + CassandraRepositoryFactory repositoryFactory = new CassandraRepositoryFactory(template); + MyPersonRepository repository = repositoryFactory.getRepository(MyPersonRepository.class); + assertThat(repository, is(notNullValue())); } interface MyPersonRepository extends Repository { - } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/querymethods/derived/QueryDerivationIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/querymethods/derived/QueryDerivationIntegrationTests.java index d7ad2bca6..80a94a2db 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/querymethods/derived/QueryDerivationIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/querymethods/derived/QueryDerivationIntegrationTests.java @@ -45,11 +45,12 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * Integration tests for query derivation through {@link PersonRepository}. - * + * * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration +@SuppressWarnings("all") public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedCassandraIntegrationTest { @Configuration @@ -68,14 +69,18 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } - @Autowired CassandraOperations template; - @Autowired PersonRepository personRepository; + @Autowired + private CassandraOperations template; - Person walter, skyler, flynn; + @Autowired + private PersonRepository personRepository; + + private Person walter; + private Person skyler; + private Person flynn; @Before public void before() { - deleteAllEntities(); Person person = new Person("Walter", "White"); @@ -87,7 +92,7 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldFindByLastname() { @@ -98,7 +103,7 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldFindByLastnameAndDynamicSort() { @@ -109,7 +114,7 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldFindByLastnameWithOrdering() { @@ -120,7 +125,7 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldFindByFirstnameAndLastname() { @@ -131,7 +136,7 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void executesCollectionQueryWithProjectionCorrectly() { @@ -146,7 +151,7 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldFindByNumberOfChildren() throws Exception { @@ -154,6 +159,7 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC assumeThat(SpringVersion.getVersion(), startsWith("4.3")); template.execute("CREATE INDEX IF NOT EXISTS person_number_of_children ON person (numberofchildren);"); + // Give Cassandra some time to build the index Thread.sleep(500); @@ -163,12 +169,13 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldFindByLocalDate() throws InterruptedException { template.execute("CREATE INDEX IF NOT EXISTS person_created_date ON person (createddate);"); + // Give Cassandra some time to build the index Thread.sleep(500); @@ -181,12 +188,13 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldUseQueryOverride() { Person otherWalter = new Person("Walter", "Black"); + personRepository.save(otherWalter); List result = personRepository.findByFirstname("Walter"); @@ -195,16 +203,16 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldUseStartsWithQuery() throws InterruptedException { - Version version = CassandraVersion.get(template.getSession()); - assumeTrue(version.isGreaterThanOrEqualTo(Version.parse("3.4"))); + assumeTrue(CassandraVersion.get(template.getSession()).isGreaterThanOrEqualTo(Version.parse("3.4"))); template.execute( "CREATE CUSTOM INDEX IF NOT EXISTS fn_starts_with ON person (nickname) USING 'org.apache.cassandra.index.sasi.SASIIndex';"); + // Give Cassandra some time to build the index Thread.sleep(500); @@ -215,17 +223,17 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC } /** - * @see DATACASS-7 + * @see DATACASS-7 */ @Test public void shouldUseContainsQuery() throws InterruptedException { - Version version = CassandraVersion.get(template.getSession()); - assumeTrue(version.isGreaterThanOrEqualTo(Version.parse("3.4"))); + assumeTrue(CassandraVersion.get(template.getSession()).isGreaterThanOrEqualTo(Version.parse("3.4"))); template.execute( "CREATE CUSTOM INDEX IF NOT EXISTS fn_contains ON person (nickname) USING 'org.apache.cassandra.index.sasi.SASIIndex'\n" + "WITH OPTIONS = { 'mode': 'CONTAINS' };"); + // Give Cassandra some time to build the index Thread.sleep(500); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/support/CassandraVersion.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/support/CassandraVersion.java index 1b9d73547..1bb06bb42 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/support/CassandraVersion.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/support/CassandraVersion.java @@ -26,7 +26,7 @@ import com.datastax.driver.core.Session; /** * Utility to retrieve the Cassandra release version. - * + * * @author Mark Paluch */ @UtilityClass @@ -34,7 +34,7 @@ public class CassandraVersion { /** * Retrieve the Cassandra release version. - * + * * @param session must not be {@literal null}. * @return the release {@link Version}. */ @@ -44,6 +44,7 @@ public class CassandraVersion { ResultSet resultSet = session.execute("SELECT release_version FROM system.local;"); Row row = resultSet.one(); + return Version.parse(row.getString(0)); } }