DATACASS-482 - Introduce usage of nullable annotations for API validation.

Mark all packages with Spring Frameworks @NonNullApi. Add Spring's @Nullable to methods, parameters and fields that take or produce null values. Adapted using code to make sure the IDE can evaluate the null flow properly. Fix Javadoc in places where an invalid null handling policy was advertised. Strengthened null requirements for types that expose null-instances.

Encapsulate KeyspaceIdentifier and CqlIdentifier with static factory methods to avoid temporary null state of fields.

Require non-null QueryOptions and provide empty option instances. Introduce methods returning non-null values (getRequired…()) for code paths known to operate on values that are available.
This commit is contained in:
Mark Paluch
2017-07-28 15:45:30 +02:00
parent 14a5f9f41b
commit 94d6a3ddc7
246 changed files with 2132 additions and 2184 deletions

View File

@@ -16,23 +16,26 @@
package org.springframework.data.cassandra;
import org.springframework.dao.QueryTimeoutException;
import org.springframework.lang.Nullable;
/**
* Spring data access exception for a Cassandra write timeout.
*
* @author Matthew T. Adams
* @author Mark Paluch
*/
public class CassandraWriteTimeoutException extends QueryTimeoutException {
private static final long serialVersionUID = -4374826375213670718L;
private String writeType;
private @Nullable String writeType;
public CassandraWriteTimeoutException(String writeType, String msg, Throwable cause) {
public CassandraWriteTimeoutException(@Nullable String writeType, String msg, Throwable cause) {
super(msg, cause);
this.writeType = writeType;
}
@Nullable
public String getWriteType() {
return writeType;
}

View File

@@ -34,6 +34,10 @@ import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;
import org.springframework.data.cassandra.core.mapping.Table;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.Session;
/**
* Base class for Spring Data Cassandra configuration using JavaConfig.
@@ -47,7 +51,21 @@ import org.springframework.data.mapping.context.MappingContext;
public abstract class AbstractCassandraConfiguration extends AbstractClusterConfiguration
implements BeanClassLoaderAware {
private ClassLoader beanClassLoader;
private @Nullable ClassLoader beanClassLoader;
/**
* Returns the initialized {@link Session} instance.
*
* @return the {@link Session}.
* @throws IllegalStateException if the session factory is not initialized.
*/
protected Session getRequiredSession() {
CassandraSessionFactoryBean factoryBean = session();
Assert.state(factoryBean.getObject() != null, "Session factory not initialized");
return factoryBean.getObject();
}
/**
* Creates a {@link CassandraSessionFactoryBean} that provides a Cassandra {@link com.datastax.driver.core.Session}.
@@ -55,8 +73,6 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
* {@link #getKeyspaceName() configured keyspace}.
*
* @return the {@link CassandraSessionFactoryBean}.
* @throws ClassNotFoundException if an error occurs initializing the initial entity set, see
* {@link #cassandraMapping()}
* @see #cluster()
* @see #cassandraConverter()
* @see #getKeyspaceName()
@@ -65,11 +81,11 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
* @see #getShutdownScripts()
*/
@Bean
public CassandraSessionFactoryBean session() throws ClassNotFoundException {
public CassandraSessionFactoryBean session() {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(cluster().getObject());
session.setCluster(getRequiredCluster());
session.setConverter(cassandraConverter());
session.setKeyspaceName(getKeyspaceName());
session.setSchemaAction(getSchemaAction());
@@ -84,13 +100,11 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
* {@link org.springframework.data.cassandra.core.CassandraTemplate}.
*
* @return {@link SessionFactory} used to initialize the Template API.
* @throws ClassNotFoundException if an error occurs initializing the initial entity set, see
* {@link #cassandraMapping()}
* @since 2.0
*/
@Bean
public SessionFactory sessionFactory() throws ClassNotFoundException {
return new DefaultSessionFactory(session().getObject());
public SessionFactory sessionFactory() {
return new DefaultSessionFactory(getRequiredSession());
}
/**
@@ -98,19 +112,21 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
* {@link #customConversions()}.
*
* @return {@link CassandraConverter} used to convert Java and Cassandra value types during the mapping process.
* @throws ClassNotFoundException if an error occurs initializing the initial entity set, see
* {@link #cassandraMapping()}
* @see #cassandraMapping()
* @see #customConversions()
*/
@Bean
public CassandraConverter cassandraConverter() throws ClassNotFoundException {
public CassandraConverter cassandraConverter() {
MappingCassandraConverter mappingCassandraConverter = new MappingCassandraConverter(cassandraMapping());
try {
MappingCassandraConverter mappingCassandraConverter = new MappingCassandraConverter(cassandraMapping());
mappingCassandraConverter.setCustomConversions(customConversions());
mappingCassandraConverter.setCustomConversions(customConversions());
return mappingCassandraConverter;
return mappingCassandraConverter;
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
}
/**
@@ -138,14 +154,17 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
CassandraMappingContext mappingContext = new CassandraMappingContext();
mappingContext.setBeanClassLoader(beanClassLoader);
if (beanClassLoader != null) {
mappingContext.setBeanClassLoader(beanClassLoader);
}
mappingContext.setInitialEntitySet(getInitialEntitySet());
CustomConversions customConversions = customConversions();
mappingContext.setCustomConversions(customConversions);
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
mappingContext.setUserTypeResolver(new SimpleUserTypeResolver(cluster().getObject(), getKeyspaceName()));
mappingContext.setUserTypeResolver(new SimpleUserTypeResolver(getRequiredCluster(), getKeyspaceName()));
return mappingContext;
}
@@ -156,7 +175,7 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
* of entity classes.
*
* @return {@link Set} of initial entity classes.
* @throws ClassNotFoundException
* @throws ClassNotFoundException if the entity scan fails.
* @see #getEntityBasePackages()
* @see CassandraEntityClassScanner
* @since 2.0
@@ -201,4 +220,5 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
public SchemaAction getSchemaAction() {
return SchemaAction.NONE;
}
}

View File

@@ -22,8 +22,11 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.AuthProvider;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.NettyOptions;
import com.datastax.driver.core.PoolingOptions;
import com.datastax.driver.core.ProtocolVersion;
@@ -48,6 +51,20 @@ import com.datastax.driver.core.policies.SpeculativeExecutionPolicy;
@Configuration
public abstract class AbstractClusterConfiguration {
/**
* Returns the initialized {@link Cluster} instance.
*
* @return the {@link Cluster}.
* @throws IllegalStateException if the cluster factory is not initialized.
*/
protected Cluster getRequiredCluster() {
CassandraClusterFactoryBean factoryBean = cluster();
Assert.state(factoryBean.getObject() != null, "Cluster factory not initialized");
return factoryBean.getObject();
}
/**
* Creates a {@link CassandraClusterFactoryBean} that provides a Cassandra {@link com.datastax.driver.core.Cluster}.
* The lifecycle of {@link CassandraClusterFactoryBean} executes {@link #getStartupScripts() startup} and
@@ -97,6 +114,7 @@ public abstract class AbstractClusterConfiguration {
* @return the {@link AddressTranslator}; may be {@literal null}.
* @since 1.5
*/
@Nullable
protected AddressTranslator getAddressTranslator() {
return null;
}
@@ -106,6 +124,7 @@ public abstract class AbstractClusterConfiguration {
*
* @return the {@link AuthProvider}, may be {@literal null}.
*/
@Nullable
protected AuthProvider getAuthProvider() {
return null;
}
@@ -116,6 +135,7 @@ public abstract class AbstractClusterConfiguration {
* @return the {@link ClusterBuilderConfigurer}; may be {@literal null}.
* @since 1.5
*/
@Nullable
protected ClusterBuilderConfigurer getClusterBuilderConfigurer() {
return null;
}
@@ -126,6 +146,7 @@ public abstract class AbstractClusterConfiguration {
* @return the cluster name; may be {@literal null}.
* @since 1.5
*/
@Nullable
protected String getClusterName() {
return null;
}
@@ -135,6 +156,7 @@ public abstract class AbstractClusterConfiguration {
*
* @return the {@link CompressionType}, may be {@literal null}.
*/
@Nullable
protected CompressionType getCompressionType() {
return null;
}
@@ -154,6 +176,7 @@ public abstract class AbstractClusterConfiguration {
*
* @return the {@link LoadBalancingPolicy}, may be {@literal null}.
*/
@Nullable
protected LoadBalancingPolicy getLoadBalancingPolicy() {
return null;
}
@@ -180,7 +203,7 @@ public abstract class AbstractClusterConfiguration {
/**
* Returns the {@link NettyOptions}. Defaults to {@link NettyOptions#DEFAULT_INSTANCE}.
*
* @return
* @return the {@link NettyOptions} to customize netty behavior.
* @since 1.5
*/
protected NettyOptions getNettyOptions() {
@@ -192,6 +215,7 @@ public abstract class AbstractClusterConfiguration {
*
* @return the {@link PoolingOptions}, may be {@literal null}.
*/
@Nullable
protected PoolingOptions getPoolingOptions() {
return null;
}
@@ -207,12 +231,13 @@ public abstract class AbstractClusterConfiguration {
}
/**
* Returns the {@link ProtocolVersion}.
* Returns the {@link ProtocolVersion}. Defaults to {@link ProtocolVersion#NEWEST_SUPPORTED}
*
* @return the {@link ProtocolVersion}, may be {@literal null}.
* @return the {@link ProtocolVersion}.
* @see ProtocolVersion#NEWEST_SUPPORTED.
*/
protected ProtocolVersion getProtocolVersion() {
return null;
return ProtocolVersion.NEWEST_SUPPORTED;
}
/**
@@ -221,6 +246,7 @@ public abstract class AbstractClusterConfiguration {
* @return the {@link QueryOptions}, may be {@literal null}.
* @since 1.5
*/
@Nullable
protected QueryOptions getQueryOptions() {
return null;
}
@@ -230,6 +256,7 @@ public abstract class AbstractClusterConfiguration {
*
* @return the {@link ReconnectionPolicy}, may be {@literal null}.
*/
@Nullable
protected ReconnectionPolicy getReconnectionPolicy() {
return null;
}
@@ -239,6 +266,7 @@ public abstract class AbstractClusterConfiguration {
*
* @return the {@link RetryPolicy}, may be {@literal null}.
*/
@Nullable
protected RetryPolicy getRetryPolicy() {
return null;
}
@@ -249,6 +277,7 @@ public abstract class AbstractClusterConfiguration {
* @return the {@link SpeculativeExecutionPolicy}; may be {@literal null}.
* @since 1.5
*/
@Nullable
protected SpeculativeExecutionPolicy getSpeculativeExecutionPolicy() {
return null;
}
@@ -258,6 +287,7 @@ public abstract class AbstractClusterConfiguration {
*
* @return the {@link SocketOptions}, may be {@literal null}.
*/
@Nullable
protected SocketOptions getSocketOptions() {
return null;
}
@@ -268,6 +298,7 @@ public abstract class AbstractClusterConfiguration {
* @return the {@link TimestampGenerator}; may be {@literal null}.
* @since 1.5
*/
@Nullable
protected TimestampGenerator getTimestampGenerator() {
return null;
}

View File

@@ -46,8 +46,8 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas
* @see DefaultBridgedReactiveSession
*/
@Bean
public ReactiveSession reactiveSession() throws Exception {
return new DefaultBridgedReactiveSession(session().getObject(), Schedulers.elastic());
public ReactiveSession reactiveSession() {
return new DefaultBridgedReactiveSession(getRequiredSession(), Schedulers.elastic());
}
/**
@@ -59,7 +59,7 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas
* @see #reactiveCassandraTemplate()
*/
@Bean
public ReactiveSessionFactory reactiveSessionFactory() throws Exception {
public ReactiveSessionFactory reactiveSessionFactory() {
return new DefaultReactiveSessionFactory(reactiveSession());
}
@@ -71,7 +71,7 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas
* @see #cassandraConverter()
*/
@Bean
public ReactiveCassandraOperations reactiveCassandraTemplate() throws Exception {
public ReactiveCassandraOperations reactiveCassandraTemplate() {
return new ReactiveCassandraTemplate(reactiveSessionFactory(), cassandraConverter());
}
@@ -82,7 +82,7 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas
* @see #reactiveSessionFactory()
*/
@Bean
public ReactiveCqlOperations reactiveCqlTemplate() throws Exception {
public ReactiveCqlOperations reactiveCqlTemplate() {
return new ReactiveCqlTemplate(reactiveSessionFactory());
}
}

View File

@@ -20,6 +20,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.SessionFactory;
import org.springframework.data.cassandra.core.cql.CqlTemplate;
import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory;
import org.springframework.util.Assert;
import com.datastax.driver.core.Session;
/**
* Spring {@link @Configuration} class used to configure a Cassandra client application
@@ -35,6 +38,20 @@ import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory
@Configuration
public abstract class AbstractSessionConfiguration extends AbstractClusterConfiguration {
/**
* Returns the initialized {@link Session} instance.
*
* @return the {@link Session}.
* @throws IllegalStateException if the session factory is not initialized.
*/
protected Session getRequiredSession() {
CassandraCqlSessionFactoryBean factoryBean = session();
Assert.state(factoryBean.getObject() != null, "Session factory not initialized");
return factoryBean.getObject();
}
/**
* Creates a {@link CassandraCqlSessionFactoryBean} that provides a Cassandra
* {@link com.datastax.driver.core.Session}.
@@ -48,7 +65,7 @@ public abstract class AbstractSessionConfiguration extends AbstractClusterConfig
CassandraCqlSessionFactoryBean bean = new CassandraCqlSessionFactoryBean();
bean.setCluster(cluster().getObject());
bean.setCluster(getRequiredCluster());
bean.setKeyspaceName(getKeyspaceName());
return bean;
@@ -63,7 +80,7 @@ public abstract class AbstractSessionConfiguration extends AbstractClusterConfig
*/
@Bean
public SessionFactory sessionFactory() {
return new DefaultSessionFactory(session().getObject());
return new DefaultSessionFactory(getRequiredSession());
}
/**

View File

@@ -36,6 +36,7 @@ import org.springframework.data.cassandra.core.cql.generator.DropKeyspaceCqlGene
import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceActionSpecification;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@@ -89,39 +90,39 @@ public class CassandraClusterFactoryBean
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
private Cluster cluster;
private ClusterBuilderConfigurer clusterBuilderConfigurer;
private @Nullable Cluster cluster;
private @Nullable ClusterBuilderConfigurer clusterBuilderConfigurer;
private AddressTranslator addressTranslator;
private AuthProvider authProvider;
private CompressionType compressionType;
private Host.StateListener hostStateListener;
private LatencyTracker latencyTracker;
private @Nullable AddressTranslator addressTranslator;
private @Nullable AuthProvider authProvider;
private @Nullable CompressionType compressionType;
private @Nullable Host.StateListener hostStateListener;
private @Nullable LatencyTracker latencyTracker;
private List<CreateKeyspaceSpecification> keyspaceCreations = new ArrayList<>();
private List<DropKeyspaceSpecification> keyspaceDrops = new ArrayList<>();
private Set<KeyspaceActionSpecification<?>> keyspaceSpecifications = new HashSet<>();
private Set<KeyspaceActionSpecification> keyspaceSpecifications = new HashSet<>();
private List<String> startupScripts = new ArrayList<>();
private List<String> shutdownScripts = new ArrayList<>();
private LoadBalancingPolicy loadBalancingPolicy;
private NettyOptions nettyOptions;
private PoolingOptions poolingOptions;
private ProtocolVersion protocolVersion;
private QueryOptions queryOptions;
private ReconnectionPolicy reconnectionPolicy;
private RetryPolicy retryPolicy;
private SpeculativeExecutionPolicy speculativeExecutionPolicy;
private SocketOptions socketOptions;
private SSLOptions sslOptions;
private TimestampGenerator timestampGenerator;
private @Nullable LoadBalancingPolicy loadBalancingPolicy;
private NettyOptions nettyOptions = NettyOptions.DEFAULT_INSTANCE;
private @Nullable PoolingOptions poolingOptions;
private @Nullable ProtocolVersion protocolVersion;
private @Nullable QueryOptions queryOptions;
private @Nullable ReconnectionPolicy reconnectionPolicy;
private @Nullable RetryPolicy retryPolicy;
private @Nullable SpeculativeExecutionPolicy speculativeExecutionPolicy;
private @Nullable SocketOptions socketOptions;
private @Nullable SSLOptions sslOptions;
private @Nullable TimestampGenerator timestampGenerator;
private String beanName;
private String clusterName;
private @Nullable String beanName;
private @Nullable String clusterName;
private String contactPoints = DEFAULT_CONTACT_POINTS;
private String password;
private String username;
private @Nullable String password;
private @Nullable String username;
/*
* (non-Javadoc)
@@ -142,7 +143,7 @@ public class CassandraClusterFactoryBean
Optional.ofNullable(addressTranslator).ifPresent(clusterBuilder::withAddressTranslator);
Optional.ofNullable(loadBalancingPolicy).ifPresent(clusterBuilder::withLoadBalancingPolicy);
Optional.ofNullable(nettyOptions).ifPresent(clusterBuilder::withNettyOptions);
clusterBuilder.withNettyOptions(nettyOptions);
Optional.ofNullable(poolingOptions).ifPresent(clusterBuilder::withPoolingOptions);
Optional.ofNullable(protocolVersion).ifPresent(clusterBuilder::withProtocolVersion);
Optional.ofNullable(queryOptions).ifPresent(clusterBuilder::withQueryOptions);
@@ -186,7 +187,7 @@ public class CassandraClusterFactoryBean
Optional.ofNullable(latencyTracker).ifPresent(cluster::register);
generateSpecificationsFromFactoryBeans();
executeSpecsAndScripts(keyspaceCreations, startupScripts);
executeSpecsAndScripts(keyspaceCreations, startupScripts, cluster);
}
/*
@@ -198,8 +199,9 @@ public class CassandraClusterFactoryBean
}
/* (non-Javadoc) */
@Nullable
private String resolveClusterName() {
return (StringUtils.hasText(clusterName) ? clusterName : beanName);
return StringUtils.hasText(clusterName) ? clusterName : beanName;
}
/*
@@ -207,9 +209,13 @@ public class CassandraClusterFactoryBean
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
@Override
public void destroy() throws Exception {
executeSpecsAndScripts(keyspaceDrops, shutdownScripts);
cluster.close();
public void destroy() {
if (cluster != null) {
executeSpecsAndScripts(keyspaceDrops, shutdownScripts, cluster);
cluster.close();
}
}
/*
@@ -266,8 +272,8 @@ public class CassandraClusterFactoryBean
});
}
protected void executeSpecsAndScripts(List<? extends KeyspaceActionSpecification<?>> kepspaceActionSpecifications,
List<String> scripts) {
protected void executeSpecsAndScripts(List<? extends KeyspaceActionSpecification> kepspaceActionSpecifications,
List<String> scripts, Cluster cluster) {
if (!CollectionUtils.isEmpty(kepspaceActionSpecifications) || !CollectionUtils.isEmpty(scripts)) {
@@ -288,7 +294,7 @@ public class CassandraClusterFactoryBean
}
}
private String toCql(KeyspaceActionSpecification<?> keyspaceActionSpecification) {
private String toCql(KeyspaceActionSpecification keyspaceActionSpecification) {
return (keyspaceActionSpecification instanceof CreateKeyspaceSpecification
? new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) keyspaceActionSpecification).toCql()
@@ -329,7 +335,7 @@ public class CassandraClusterFactoryBean
*
* @param compressionType the {@link CompressionType} used by the new cluster.
*/
public void setCompressionType(CompressionType compressionType) {
public void setCompressionType(@Nullable CompressionType compressionType) {
this.compressionType = compressionType;
}
@@ -338,7 +344,7 @@ public class CassandraClusterFactoryBean
*
* @param poolingOptions the {@link PoolingOptions} used by the new cluster.
*/
public void setPoolingOptions(PoolingOptions poolingOptions) {
public void setPoolingOptions(@Nullable PoolingOptions poolingOptions) {
this.poolingOptions = poolingOptions;
}
@@ -348,7 +354,7 @@ public class CassandraClusterFactoryBean
* @param protocolVersion the {@link ProtocolVersion} used by the new cluster.
* @since 1.4
*/
public void setProtocolVersion(ProtocolVersion protocolVersion) {
public void setProtocolVersion(@Nullable ProtocolVersion protocolVersion) {
this.protocolVersion = protocolVersion;
}
@@ -357,7 +363,7 @@ public class CassandraClusterFactoryBean
*
* @param socketOptions the {@link SocketOptions} used by the new cluster.
*/
public void setSocketOptions(SocketOptions socketOptions) {
public void setSocketOptions(@Nullable SocketOptions socketOptions) {
this.socketOptions = socketOptions;
}
@@ -366,7 +372,7 @@ public class CassandraClusterFactoryBean
*
* @param queryOptions the {@link QueryOptions} used by the new cluster.
*/
public void setQueryOptions(QueryOptions queryOptions) {
public void setQueryOptions(@Nullable QueryOptions queryOptions) {
this.queryOptions = queryOptions;
}
@@ -375,7 +381,7 @@ public class CassandraClusterFactoryBean
*
* @param authProvider the {@link AuthProvider} used by the new cluster.
*/
public void setAuthProvider(AuthProvider authProvider) {
public void setAuthProvider(@Nullable AuthProvider authProvider) {
this.authProvider = authProvider;
}
@@ -394,7 +400,7 @@ public class CassandraClusterFactoryBean
*
* @param loadBalancingPolicy the {@link LoadBalancingPolicy} used by the new cluster.
*/
public void setLoadBalancingPolicy(LoadBalancingPolicy loadBalancingPolicy) {
public void setLoadBalancingPolicy(@Nullable LoadBalancingPolicy loadBalancingPolicy) {
this.loadBalancingPolicy = loadBalancingPolicy;
}
@@ -403,7 +409,7 @@ public class CassandraClusterFactoryBean
*
* @param reconnectionPolicy the {@link ReconnectionPolicy} used by the new cluster.
*/
public void setReconnectionPolicy(ReconnectionPolicy reconnectionPolicy) {
public void setReconnectionPolicy(@Nullable ReconnectionPolicy reconnectionPolicy) {
this.reconnectionPolicy = reconnectionPolicy;
}
@@ -412,7 +418,7 @@ public class CassandraClusterFactoryBean
*
* @param retryPolicy the {@link RetryPolicy} used by the new cluster.
*/
public void setRetryPolicy(RetryPolicy retryPolicy) {
public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
}
@@ -499,14 +505,14 @@ public class CassandraClusterFactoryBean
/**
* @param keyspaceSpecifications The {@link KeyspaceActionSpecification} to set.
*/
public void setKeyspaceSpecifications(Set<KeyspaceActionSpecification<?>> keyspaceSpecifications) {
public void setKeyspaceSpecifications(Set<KeyspaceActionSpecification> keyspaceSpecifications) {
this.keyspaceSpecifications = keyspaceSpecifications;
}
/**
* @return the {@link KeyspaceActionSpecification} associated with this factory.
*/
public Set<KeyspaceActionSpecification<?>> getKeyspaceSpecifications() {
public Set<KeyspaceActionSpecification> getKeyspaceSpecifications() {
return keyspaceSpecifications;
}
@@ -576,7 +582,7 @@ public class CassandraClusterFactoryBean
* @see com.datastax.driver.core.policies.AddressTranslator
* @since 1.5
*/
public void setAddressTranslator(AddressTranslator addressTranslator) {
public void setAddressTranslator(@Nullable AddressTranslator addressTranslator) {
this.addressTranslator = addressTranslator;
}
@@ -590,7 +596,7 @@ public class CassandraClusterFactoryBean
* {@link com.datastax.driver.core.Cluster.Builder}.
* @see org.springframework.data.cql.config.ClusterBuilderConfigurer
*/
public void setClusterBuilderConfigurer(ClusterBuilderConfigurer clusterBuilderConfigurer) {
public void setClusterBuilderConfigurer(@Nullable ClusterBuilderConfigurer clusterBuilderConfigurer) {
this.clusterBuilderConfigurer = clusterBuilderConfigurer;
}
@@ -601,7 +607,7 @@ public class CassandraClusterFactoryBean
* @see com.datastax.driver.core.Cluster.Builder#withClusterName(String)
* @since 1.5
*/
public void setClusterName(String clusterName) {
public void setClusterName(@Nullable String clusterName) {
this.clusterName = clusterName;
}
@@ -625,7 +631,7 @@ public class CassandraClusterFactoryBean
* @see com.datastax.driver.core.policies.SpeculativeExecutionPolicy
* @since 1.5
*/
public void setSpeculativeExecutionPolicy(SpeculativeExecutionPolicy speculativeExecutionPolicy) {
public void setSpeculativeExecutionPolicy(@Nullable SpeculativeExecutionPolicy speculativeExecutionPolicy) {
this.speculativeExecutionPolicy = speculativeExecutionPolicy;
}
@@ -637,7 +643,7 @@ public class CassandraClusterFactoryBean
* @see com.datastax.driver.core.TimestampGenerator
* @since 1.5
*/
public void setTimestampGenerator(TimestampGenerator timestampGenerator) {
public void setTimestampGenerator(@Nullable TimestampGenerator timestampGenerator) {
this.timestampGenerator = timestampGenerator;
}

View File

@@ -30,6 +30,7 @@ import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceActionSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceAttributes;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -205,7 +206,7 @@ class CassandraCqlClusterParser extends AbstractBeanDefinitionParser {
* @param element {@link Element} to parse.
* @param builder The {@link BeanDefinitionBuilder} to add the replication to
*/
private void parseReplication(Element element, BeanDefinitionBuilder builder) {
private void parseReplication(@Nullable Element element, BeanDefinitionBuilder builder) {
ManagedList<String> networkTopologyDataCenters = new ManagedList<>();
ManagedList<String> networkTopologyReplicationFactors = new ManagedList<>();

View File

@@ -20,6 +20,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
@@ -28,13 +30,11 @@ import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.cassandra.core.cql.CassandraExceptionTranslator;
import org.springframework.data.cassandra.core.cql.CqlOperations;
import org.springframework.data.cassandra.core.cql.CqlTemplate;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Session;
@@ -45,6 +45,7 @@ import com.datastax.driver.core.Session;
* @author Alex Shvid
* @author Matthew T. Adams
* @author John Blum
* @author Mark Paluch
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
@@ -60,15 +61,15 @@ public class CassandraCqlSessionFactoryBean
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
private Cluster cluster;
private @Nullable Cluster cluster;
private List<String> startupScripts = Collections.emptyList();
private List<String> shutdownScripts = Collections.emptyList();
private Session session;
private @Nullable Session session;
private String keyspaceName;
private @Nullable String keyspaceName;
/*
* (non-Javadoc)
@@ -83,7 +84,7 @@ public class CassandraCqlSessionFactoryBean
}
/* (non-Javadoc) */
Session connect(String keyspaceName) {
Session connect(@Nullable String keyspaceName) {
return (StringUtils.hasText(keyspaceName) ? getCluster().connect(keyspaceName) : getCluster().connect());
}
@@ -178,7 +179,9 @@ public class CassandraCqlSessionFactoryBean
* @see #getCluster()
*/
public void setCluster(Cluster cluster) {
Assert.notNull(cluster, "Cluster must not be null");
this.cluster = cluster;
}
@@ -191,18 +194,20 @@ public class CassandraCqlSessionFactoryBean
* @see #setCluster(Cluster)
*/
protected Cluster getCluster() {
Assert.state(this.cluster != null, "Cluster was not properly initialized");
return this.cluster;
}
/**
* Sets the name of the Cassandra Keyspace to connect to. Passing {@code null}, an empty String, or whitespace will
* Sets the name of the Cassandra Keyspace to connect to. Passing {@literal null}, an empty String, or whitespace will
* cause the Cassandra System Keyspace to be used.
*
* @param keyspaceName a String indicating the name of the Keyspace in which to connect.
* @see #getKeyspaceName()
*/
public void setKeyspaceName(String keyspaceName) {
public void setKeyspaceName(@Nullable String keyspaceName) {
this.keyspaceName = keyspaceName;
}
@@ -212,6 +217,7 @@ public class CassandraCqlSessionFactoryBean
* @return the name of the Cassandra Keyspace to connect to as a String.
* @see #setKeyspaceName(String)
*/
@Nullable
protected String getKeyspaceName() {
return this.keyspaceName;
}
@@ -235,7 +241,7 @@ public class CassandraCqlSessionFactoryBean
/**
* Sets CQL scripts to be executed immediately after the session is connected.
*/
public void setStartupScripts(List<String> scripts) {
public void setStartupScripts(@Nullable List<String> scripts) {
this.startupScripts = (scripts != null ? new ArrayList<>(scripts) : Collections.emptyList());
}
@@ -249,7 +255,7 @@ public class CassandraCqlSessionFactoryBean
/**
* Sets CQL scripts to be executed immediately before the session is shutdown.
*/
public void setShutdownScripts(List<String> scripts) {
public void setShutdownScripts(@Nullable List<String> scripts) {
this.shutdownScripts = (scripts != null ? new ArrayList<>(scripts) : Collections.emptyList());
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.config;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.cassandra.core.cql.CqlTemplate;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.Session;
@@ -30,8 +31,9 @@ import com.datastax.driver.core.Session;
*/
public class CassandraCqlTemplateFactoryBean implements FactoryBean<CqlTemplate>, InitializingBean {
private CqlTemplate template;
private Session session;
private @Nullable CqlTemplate template;
private @Nullable Session session;
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()

View File

@@ -28,51 +28,110 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.cassandra.core.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.core.mapping.Table;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Scans packages for Cassandra entities.
* Scans packages for Cassandra entities. The entity scanner scans for entity classes annotated with
* {@link #getEntityAnnotations() entity annotations} on the class path using either base package names, base package
* classes or both.
*
* @author Matthew T. Adams
* @author Mark Paluch
* @see ClassUtils#forName(String, ClassLoader)
*/
public class CassandraEntityClassScanner {
private Set<String> entityBasePackages = new HashSet<>();
private Set<Class<?>> entityBasePackageClasses = new HashSet<>();
private @Nullable ClassLoader beanClassLoader;
/**
* Scan one or more base packages for entity classes. Classes are loaded using the current class loader.
*
* @param entityBasePackages must not be {@literal null}.
* @return
* @throws ClassNotFoundException
*/
public static Set<Class<?>> scan(String... entityBasePackages) throws ClassNotFoundException {
return new CassandraEntityClassScanner(entityBasePackages).scanForEntityClasses();
}
/**
* Scan one or more base packages for entity classes. Classes are loaded using the current class loader.
*
* @param entityBasePackageClasses must not be {@literal null}.
* @return
* @throws ClassNotFoundException
*/
public static Set<Class<?>> scan(Class<?>... entityBasePackageClasses) throws ClassNotFoundException {
return new CassandraEntityClassScanner(entityBasePackageClasses).scanForEntityClasses();
}
/**
* Scan one or more base packages for entity classes. Classes are loaded using the current class loader.
*
* @param entityBasePackages must not be {@literal null}.
* @return
* @throws ClassNotFoundException
*/
public static Set<Class<?>> scan(Collection<String> entityBasePackages) throws ClassNotFoundException {
return new CassandraEntityClassScanner(entityBasePackages).scanForEntityClasses();
}
/**
* Scan one or more base packages for entity classes. Classes are loaded using the current class loader.
*
* @param entityBasePackages must not be {@literal null}.
* @param entityBasePackageClasses must not be {@literal null}.
* @return
* @throws ClassNotFoundException
*/
public static Set<Class<?>> scan(Collection<String> entityBasePackages, Collection<Class<?>> entityBasePackageClasses)
throws ClassNotFoundException {
return new CassandraEntityClassScanner(entityBasePackages, entityBasePackageClasses).scanForEntityClasses();
}
protected Set<String> entityBasePackages = new HashSet<>();
protected Set<Class<?>> entityBasePackageClasses = new HashSet<>();
protected ClassLoader beanClassLoader;
/**
* Creates a new {@link CassandraEntityClassScanner}.
*/
public CassandraEntityClassScanner() {}
/**
* Creates a new {@link CassandraEntityClassScanner} given {@code entityBasePackageClasses}.
*
* @param entityBasePackageClasses must not be {@literal null}.
*/
public CassandraEntityClassScanner(Class<?>... entityBasePackageClasses) {
this(null, Arrays.asList(entityBasePackageClasses));
setEntityBasePackageClasses(Arrays.asList(entityBasePackageClasses));
}
/**
* Creates a new {@link CassandraEntityClassScanner} given {@code entityBasePackages}.
*
* @param entityBasePackages must not be {@literal null}.
*/
public CassandraEntityClassScanner(String... entityBasePackages) {
this(Arrays.asList(entityBasePackages));
}
/**
* Creates a new {@link CassandraEntityClassScanner} given {@code entityBasePackages}.
*
* @param entityBasePackages must not be {@literal null}.
*/
public CassandraEntityClassScanner(Collection<String> entityBasePackages) {
this(entityBasePackages, null);
setEntityBasePackages(entityBasePackages);
}
/**
* Creates a new {@link CassandraEntityClassScanner} given {@code entityBasePackages} and
* {@code entityBasePackageClasses}.
*
* @param entityBasePackages must not be {@literal null}.
* @param entityBasePackageClasses must not be {@literal null}.
*/
public CassandraEntityClassScanner(Collection<String> entityBasePackages,
Collection<Class<?>> entityBasePackageClasses) {
@@ -80,23 +139,43 @@ public class CassandraEntityClassScanner {
setEntityBasePackageClasses(entityBasePackageClasses);
}
/**
* @return base package names used for the entity scan.
*/
public Set<String> getEntityBasePackages() {
return Collections.unmodifiableSet(entityBasePackages);
}
/**
* Set the base package names to be used for the entity scan.
*
* @param entityBasePackages must not be {@literal null}.
*/
public void setEntityBasePackages(Collection<String> entityBasePackages) {
this.entityBasePackages = entityBasePackages == null ? new HashSet<>() : new HashSet<>(entityBasePackages);
this.entityBasePackages = new HashSet<>(entityBasePackages);
}
/**
* @return base package classes used for the entity scan.
*/
public Set<Class<?>> getEntityBasePackageClasses() {
return Collections.unmodifiableSet(entityBasePackageClasses);
}
/**
* Set the base package classes to be used for the entity scan.
*
* @param entityBasePackageClasses must not be {@literal null}.
*/
public void setEntityBasePackageClasses(Collection<Class<?>> entityBasePackageClasses) {
this.entityBasePackageClasses = entityBasePackageClasses == null ? new HashSet<>()
: new HashSet<>(entityBasePackageClasses);
this.entityBasePackageClasses = new HashSet<>(entityBasePackageClasses);
}
/**
* Set the bean {@link ClassLoader} to load class candidates discovered by the class path scan.
*
* @param beanClassLoader must not be {@literal null}.
*/
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
@@ -127,14 +206,20 @@ public class CassandraEntityClassScanner {
HashSet<Class<?>> classes = new HashSet<>();
if (StringUtils.hasText(basePackage)) {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
false);
for (Class<? extends Annotation> annoClass : getEntityAnnotations()) {
componentProvider.addIncludeFilter(new AnnotationTypeFilter(annoClass));
}
if (StringUtils.isEmpty(basePackage)) {
return classes;
}
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
false);
for (Class<? extends Annotation> annotation : getEntityAnnotations()) {
componentProvider.addIncludeFilter(new AnnotationTypeFilter(annotation));
}
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
if (candidate.getBeanClassName() != null) {
classes.add(ClassUtils.forName(candidate.getBeanClassName(), beanClassLoader));
}
}
@@ -142,8 +227,14 @@ public class CassandraEntityClassScanner {
return classes;
}
/**
* @return entity annotations.
* @see Table
* @see Persistent
* @see PrimaryKeyClass
*/
@SuppressWarnings("unchecked")
public Class<? extends Annotation>[] getEntityAnnotations() {
protected Class<? extends Annotation>[] getEntityAnnotations() {
return new Class[] { Table.class, Persistent.class, PrimaryKeyClass.class };
}
}

View File

@@ -97,10 +97,7 @@ class CassandraMappingContextParser extends AbstractSingleBeanDefinitionParser {
DomUtils.getChildElementsByTagName(element, "entity").forEach(entity -> {
EntityMapping entityMapping = parseEntity(entity);
if (entityMapping != null) {
mappings.add(entityMapping);
}
mappings.add(entityMapping);
});
List<Element> userTypeResolvers = DomUtils.getChildElementsByTagName(element, "user-type-resolver");

View File

@@ -28,14 +28,16 @@ import org.w3c.dom.Element;
* Ensures that a {@link CassandraMappingBeanFactoryPostProcessor} is registered.
*
* @author Matthew T. Adams
* @author Mark Paluch
*/
@Deprecated
class CassandraMappingXmlBeanFactoryPostProcessorRegistrar {
/**
* Ensures that a {@link CassandraMappingBeanFactoryPostProcessor} is registered. This method is a no-op if one is
* already registered.
*/
public static void ensureRegistration(Element element, ParserContext parserContext) {
static void ensureRegistration(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
if (!(registry instanceof GenericApplicationContext)) {

View File

@@ -21,6 +21,7 @@ import org.springframework.data.cassandra.core.CassandraPersistentEntitySchemaCr
import org.springframework.data.cassandra.core.CassandraPersistentEntitySchemaDropper;
import org.springframework.data.cassandra.core.convert.CassandraConverter;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -40,9 +41,9 @@ public class CassandraSessionFactoryBean extends CassandraCqlSessionFactoryBean
protected static final boolean DEFAULT_DROP_TABLES = false;
protected static final boolean DEFAULT_DROP_UNUSED_TABLES = false;
private CassandraAdminOperations admin;
private @Nullable CassandraAdminOperations admin;
private CassandraConverter converter;
private @Nullable CassandraConverter converter;
private SchemaAction schemaAction = SchemaAction.NONE;
@@ -107,6 +108,7 @@ public class CassandraSessionFactoryBean extends CassandraCqlSessionFactoryBean
/**
* @return the {@link CassandraConverter}.
*/
@Nullable
public CassandraConverter getConverter() {
return this.converter;
}
@@ -114,6 +116,7 @@ public class CassandraSessionFactoryBean extends CassandraCqlSessionFactoryBean
/**
* @return the {@link CassandraMappingContext}.
*/
@Nullable
protected CassandraMappingContext getMappingContext() {
return getConverter().getMappingContext();
}

View File

@@ -22,6 +22,7 @@ import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.cassandra.core.convert.CassandraConverter;
import org.springframework.data.cassandra.core.cql.CqlOperations;
import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.Session;
@@ -34,11 +35,11 @@ import com.datastax.driver.core.Session;
*/
public class CassandraTemplateFactoryBean implements FactoryBean<CassandraTemplate>, InitializingBean {
protected SessionFactory sessionFactory;
protected @Nullable SessionFactory sessionFactory;
protected CqlOperations cqlOperations;
protected @Nullable CqlOperations cqlOperations;
protected CassandraConverter converter;
protected @Nullable CassandraConverter converter;
/*
* (non-Javadoc)

View File

@@ -32,6 +32,7 @@ import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceActionSpecif
import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption;
import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption.ReplicationStrategy;
import org.springframework.data.cassandra.core.cql.keyspace.Option;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -42,16 +43,16 @@ import org.springframework.util.Assert;
* @author David Webb
*/
public class KeyspaceActionSpecificationFactoryBean
implements FactoryBean<Set<KeyspaceActionSpecification<?>>>, InitializingBean, DisposableBean {
implements FactoryBean<Set<KeyspaceActionSpecification>>, InitializingBean, DisposableBean {
private KeyspaceAction action;
private @Nullable KeyspaceAction action;
private String name;
private @Nullable String name;
private List<String> networkTopologyDataCenters = new LinkedList<>();
private List<String> networkTopologyReplicationFactors = new LinkedList<>();
private ReplicationStrategy replicationStrategy;
private @Nullable ReplicationStrategy replicationStrategy;
private long replicationFactor;
@@ -59,7 +60,7 @@ public class KeyspaceActionSpecificationFactoryBean
private boolean ifNotExists = false;
private Set<KeyspaceActionSpecification<?>> specs = new HashSet<>();
private Set<KeyspaceActionSpecification> specs = new HashSet<>();
/* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
@@ -68,10 +69,10 @@ public class KeyspaceActionSpecificationFactoryBean
public void destroy() {
action = null;
name = null;
networkTopologyDataCenters = null;
networkTopologyReplicationFactors = null;
networkTopologyDataCenters = new LinkedList<>();
networkTopologyReplicationFactors = new LinkedList<>();
replicationStrategy = null;
specs = null;
specs = new HashSet<>();
}
/* (non-Javadoc)
@@ -102,8 +103,8 @@ public class KeyspaceActionSpecificationFactoryBean
*/
private CreateKeyspaceSpecification generateCreateKeyspaceSpecification() {
CreateKeyspaceSpecification create = new CreateKeyspaceSpecification();
create.name(name).ifNotExists(ifNotExists).with(KeyspaceOption.DURABLE_WRITES, durableWrites);
CreateKeyspaceSpecification create = CreateKeyspaceSpecification.createKeyspace(name).ifNotExists(ifNotExists)
.with(KeyspaceOption.DURABLE_WRITES, durableWrites);
Map<Option, Object> replicationStrategyMap = new HashMap<>();
replicationStrategyMap.put(new DefaultOption("class", String.class, true, false, true),
@@ -133,16 +134,14 @@ public class KeyspaceActionSpecificationFactoryBean
* @return The {@link DropKeyspaceSpecification}
*/
private DropKeyspaceSpecification generateDropKeyspaceSpecification() {
DropKeyspaceSpecification drop = new DropKeyspaceSpecification();
drop.name(getName());
return drop;
return DropKeyspaceSpecification.dropKeyspace(getName());
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@Override
public Set<KeyspaceActionSpecification<?>> getObject() throws Exception {
public Set<KeyspaceActionSpecification> getObject() {
return specs;
}
@@ -165,6 +164,7 @@ public class KeyspaceActionSpecificationFactoryBean
/**
* @return Returns the name.
*/
@Nullable
public String getName() {
return name;
}
@@ -193,6 +193,7 @@ public class KeyspaceActionSpecificationFactoryBean
/**
* @return Returns the action.
*/
@Nullable
public KeyspaceAction getAction() {
return action;
}
@@ -221,6 +222,7 @@ public class KeyspaceActionSpecificationFactoryBean
/**
* @return Returns the replicationStrategy.
*/
@Nullable
public ReplicationStrategy getReplicationStrategy() {
return replicationStrategy;
}

View File

@@ -19,6 +19,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.w3c.dom.Attr;
@@ -29,11 +30,6 @@ import org.w3c.dom.Element;
*
* @author John Blum
* @author Mark Paluch
* @see org.springframework.beans.factory.config.BeanDefinition
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.beans.factory.xml.ParserContext
* @see org.w3c.dom.Attr
* @see org.w3c.dom.Element
*/
abstract class ParsingUtils {
@@ -129,7 +125,7 @@ abstract class ParsingUtils {
* {@link #addProperty(BeanDefinitionBuilder, String, String, String, boolean, boolean)}.
*/
public static void addOptionalPropertyValue(BeanDefinitionBuilder builder, String propertyName, Element element,
String attributeName, String defaultValue) {
String attributeName, @Nullable String defaultValue) {
addProperty(builder, propertyName, element.getAttribute(attributeName), defaultValue, false, false);
}
@@ -233,7 +229,7 @@ abstract class ParsingUtils {
* @see BeanDefinitionBuilder#addPropertyValue(String, Object)
*/
public static BeanDefinitionBuilder addProperty(BeanDefinitionBuilder builder, String propertyName, String value,
String defaultValue, boolean required, boolean reference) {
@Nullable String defaultValue, boolean required, boolean reference) {
Assert.notNull(builder, "BeanDefinitionBuilder must not be null");
Assert.hasText(propertyName, "Property name must not be null");

View File

@@ -23,6 +23,7 @@ import java.util.concurrent.Executor;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
import com.datastax.driver.core.HostDistance;
@@ -39,7 +40,7 @@ import com.datastax.driver.core.PoolingOptions;
* @see org.springframework.beans.factory.InitializingBean
* @see com.datastax.driver.core.PoolingOptions
*/
@SuppressWarnings("unused")
@SuppressWarnings({ "unused", "WeakerAccess" })
public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, InitializingBean {
private static final PoolingOptions DEFAULT = new PoolingOptions();
@@ -56,26 +57,26 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
GET_MAX_QUEUE_SIZE = Optional.ofNullable(ReflectionUtils.findMethod(PoolingOptions.class, "getMaxQueueSize"));
}
private Executor initializationExecutor;
private @Nullable Executor initializationExecutor;
private int heartbeatIntervalSeconds;
private int idleTimeoutSeconds;
private Integer localCoreConnections;
private Integer localMaxConnections;
private Integer localMaxSimultaneousRequests;
private Integer localMinSimultaneousRequests;
private @Nullable Integer localCoreConnections;
private @Nullable Integer localMaxConnections;
private @Nullable Integer localMaxSimultaneousRequests;
private @Nullable Integer localMinSimultaneousRequests;
// Deprecated since Cassandra Driver 3.1.1
private int poolTimeoutMilliseconds;
// Available since Cassandra Driver 3.1.1
private int maxQueueSize;
private Integer remoteCoreConnections;
private Integer remoteMaxConnections;
private Integer remoteMaxSimultaneousRequests;
private Integer remoteMinSimultaneousRequests;
private @Nullable Integer remoteCoreConnections;
private @Nullable Integer remoteMaxConnections;
private @Nullable Integer remoteMaxSimultaneousRequests;
private @Nullable Integer remoteMinSimultaneousRequests;
private PoolingOptions poolingOptions;
private @Nullable PoolingOptions poolingOptions;
/*
* (non-Javadoc)
@@ -137,7 +138,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* @see PoolingOptionsFactoryBean.LocalHostDistancePoolingOptions
*/
protected HostDistancePoolingOptions newLocalHostDistancePoolingOptions() {
return LocalHostDistancePoolingOptions.create(getLocalCoreConnections(), getLocalMaxConnections(),
return new LocalHostDistancePoolingOptions(getLocalCoreConnections(), getLocalMaxConnections(),
getLocalMaxSimultaneousRequests(), getLocalMinSimultaneousRequests());
}
@@ -153,7 +154,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* @see PoolingOptionsFactoryBean.RemoteHostDistancePoolingOptions
*/
protected HostDistancePoolingOptions newRemoteHostDistancePoolingOptions() {
return RemoteHostDistancePoolingOptions.create(getRemoteCoreConnections(), getRemoteMaxConnections(),
return new RemoteHostDistancePoolingOptions(getRemoteCoreConnections(), getRemoteMaxConnections(),
getRemoteMaxSimultaneousRequests(), getRemoteMinSimultaneousRequests());
}
@@ -260,6 +261,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @return the {@code initializationExecutor}.
*/
@Nullable
public Executor getInitializationExecutor() {
return initializationExecutor;
}
@@ -305,7 +307,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @param localCoreConnections core number of local connections per host.
*/
public void setLocalCoreConnections(Integer localCoreConnections) {
public void setLocalCoreConnections(@Nullable Integer localCoreConnections) {
this.localCoreConnections = localCoreConnections;
}
@@ -314,6 +316,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @return the {@code localCoreConnections).
*/
@Nullable
public Integer getLocalCoreConnections() {
return localCoreConnections;
}
@@ -323,7 +326,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @param localMaxConnections max number of local connections per host.
*/
public void setLocalMaxConnections(Integer localMaxConnections) {
public void setLocalMaxConnections(@Nullable Integer localMaxConnections) {
this.localMaxConnections = localMaxConnections;
}
@@ -332,6 +335,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @return the {@code localMaxConnections}.
*/
@Nullable
public Integer getLocalMaxConnections() {
return localMaxConnections;
}
@@ -341,7 +345,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @param localMaxSimultaneousRequests max number of requests for local connections.
*/
public void setLocalMaxSimultaneousRequests(Integer localMaxSimultaneousRequests) {
public void setLocalMaxSimultaneousRequests(@Nullable Integer localMaxSimultaneousRequests) {
this.localMaxSimultaneousRequests = localMaxSimultaneousRequests;
}
@@ -350,6 +354,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @return the {@code localMaxSimultaneousRequests}.
*/
@Nullable
public Integer getLocalMaxSimultaneousRequests() {
return localMaxSimultaneousRequests;
}
@@ -360,7 +365,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @param localMinSimultaneousRequests threshold triggering the creation of local connections to a host.
*/
public void setLocalMinSimultaneousRequests(Integer localMinSimultaneousRequests) {
public void setLocalMinSimultaneousRequests(@Nullable Integer localMinSimultaneousRequests) {
this.localMinSimultaneousRequests = localMinSimultaneousRequests;
}
@@ -370,6 +375,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @return the {@code localMinSimultaneousRequests}.
*/
@Nullable
public Integer getLocalMinSimultaneousRequests() {
return localMinSimultaneousRequests;
}
@@ -379,7 +385,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @param remoteCoreConnections core number of remote connections per host.
*/
public void setRemoteCoreConnections(Integer remoteCoreConnections) {
public void setRemoteCoreConnections(@Nullable Integer remoteCoreConnections) {
this.remoteCoreConnections = remoteCoreConnections;
}
@@ -388,6 +394,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @return the {@code remoteCoreConnections).
*/
@Nullable
public Integer getRemoteCoreConnections() {
return remoteCoreConnections;
}
@@ -397,7 +404,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @param remoteMaxConnections max number of remote connections per host.
*/
public void setRemoteMaxConnections(Integer remoteMaxConnections) {
public void setRemoteMaxConnections(@Nullable Integer remoteMaxConnections) {
this.remoteMaxConnections = remoteMaxConnections;
}
@@ -406,6 +413,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @return the {@code remoteMaxConnections}.
*/
@Nullable
public Integer getRemoteMaxConnections() {
return remoteMaxConnections;
}
@@ -415,7 +423,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @param remoteMaxSimultaneousRequests max number of requests for local connections.
*/
public void setRemoteMaxSimultaneousRequests(Integer remoteMaxSimultaneousRequests) {
public void setRemoteMaxSimultaneousRequests(@Nullable Integer remoteMaxSimultaneousRequests) {
this.remoteMaxSimultaneousRequests = remoteMaxSimultaneousRequests;
}
@@ -424,6 +432,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @return the {@code remoteMaxSimultaneousRequests}.
*/
@Nullable
public Integer getRemoteMaxSimultaneousRequests() {
return remoteMaxSimultaneousRequests;
}
@@ -434,7 +443,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @param remoteMinSimultaneousRequests threshold triggering the creation of remote connections to a host.
*/
public void setRemoteMinSimultaneousRequests(Integer remoteMinSimultaneousRequests) {
public void setRemoteMinSimultaneousRequests(@Nullable Integer remoteMinSimultaneousRequests) {
this.remoteMinSimultaneousRequests = remoteMinSimultaneousRequests;
}
@@ -444,6 +453,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @return the {@code remoteMinSimultaneousRequests}.
*/
@Nullable
public Integer getRemoteMinSimultaneousRequests() {
return remoteMinSimultaneousRequests;
}
@@ -457,10 +467,10 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*/
protected static abstract class HostDistancePoolingOptions {
private final Integer coreConnectionsPerHost;
private final Integer maxConnectionsPerHost;
private final Integer maxRequestsPerConnection;
private final Integer newConnectionThreshold;
private final @Nullable Integer coreConnectionsPerHost;
private final @Nullable Integer maxConnectionsPerHost;
private final @Nullable Integer maxRequestsPerConnection;
private final @Nullable Integer newConnectionThreshold;
/**
* Constructs an instance of {@link HostDistancePoolingOptions} with {@link PoolingOptions} connection settings
@@ -471,8 +481,9 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* @param maxRequestsPerConnection maximum number of requests per connection.
* @param newConnectionThreshold threshold that triggers the creation of a new connection to a host.
*/
protected HostDistancePoolingOptions(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost,
Integer maxRequestsPerConnection, Integer newConnectionThreshold) {
protected HostDistancePoolingOptions(@Nullable Integer coreConnectionsPerHost,
@Nullable Integer maxConnectionsPerHost, @Nullable Integer maxRequestsPerConnection,
@Nullable Integer newConnectionThreshold) {
this.coreConnectionsPerHost = coreConnectionsPerHost;
this.maxConnectionsPerHost = maxConnectionsPerHost;
@@ -492,12 +503,10 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* (non-Javadoc)
* @see com.datastax.driver.core.PoolingOptions#setCoreConnectionsPerHost(HostDistance, int)
*/
PoolingOptions setCoreConnectionsPerHost(PoolingOptions poolingOptions) {
void setCoreConnectionsPerHost(PoolingOptions poolingOptions) {
if (coreConnectionsPerHost != null) {
poolingOptions.setCoreConnectionsPerHost(getHostDistance(), coreConnectionsPerHost);
}
return poolingOptions;
}
/**
@@ -507,6 +516,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* @see com.datastax.driver.core.PoolingOptions#getCoreConnectionsPerHost(HostDistance)
* @see #getHostDistance()
*/
@Nullable
protected Integer getCoreConnectionsPerHost() {
return coreConnectionsPerHost;
}
@@ -515,12 +525,10 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* (non-Javadoc)
* @see com.datastax.driver.core.PoolingOptions#setMaxConnectionsPerHost(HostDistance, int)
*/
PoolingOptions setMaxConnectionsPerHost(PoolingOptions poolingOptions) {
void setMaxConnectionsPerHost(PoolingOptions poolingOptions) {
if (maxConnectionsPerHost != null) {
poolingOptions.setMaxConnectionsPerHost(getHostDistance(), maxConnectionsPerHost);
}
return poolingOptions;
}
/**
@@ -530,6 +538,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* @see com.datastax.driver.core.PoolingOptions#getMaxConnectionsPerHost(HostDistance)
* @see #getHostDistance()
*/
@Nullable
protected Integer getMaxConnectionsPerHost() {
return maxConnectionsPerHost;
}
@@ -538,12 +547,10 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* (non-Javadoc)
* @see com.datastax.driver.core.PoolingOptions#setMaxRequestsPerConnection(HostDistance, int)
*/
PoolingOptions setMaxRequestsPerConnection(PoolingOptions poolingOptions) {
void setMaxRequestsPerConnection(PoolingOptions poolingOptions) {
if (maxRequestsPerConnection != null) {
poolingOptions.setMaxRequestsPerConnection(getHostDistance(), maxRequestsPerConnection);
}
return poolingOptions;
}
/**
@@ -553,6 +560,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* @see com.datastax.driver.core.PoolingOptions#getMaxRequestsPerConnection(HostDistance)
* @see #getHostDistance()
*/
@Nullable
protected Integer getMaxRequestsPerConnection() {
return maxRequestsPerConnection;
}
@@ -564,7 +572,8 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*
* @see com.datastax.driver.core.PoolingOptions#setNewConnectionThreshold(HostDistance, int)
*/
PoolingOptions setNewConnectionThreshold(PoolingOptions poolingOptions) {
void setNewConnectionThreshold(PoolingOptions poolingOptions) {
if (newConnectionThreshold != null) {
int currentNewConnectionThreshold = poolingOptions.getNewConnectionThreshold(getHostDistance());
@@ -572,8 +581,6 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
poolingOptions.setNewConnectionThreshold(getHostDistance(), newConnectionThreshold);
}
}
return poolingOptions;
}
/**
@@ -583,6 +590,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* @see com.datastax.driver.core.PoolingOptions#getNewConnectionThreshold(HostDistance)
* @see #getHostDistance()
*/
@Nullable
protected Integer getNewConnectionThreshold() {
return newConnectionThreshold;
}
@@ -611,22 +619,6 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*/
static class LocalHostDistancePoolingOptions extends HostDistancePoolingOptions {
/**
* Creates an instance of {@link LocalHostDistancePoolingOptions} initialized with {@link PoolingOptions} based on
* {@link HostDistance#LOCAL}.
*
* @param coreConnectionsPerHost core number of connections per host.
* @param maxConnectionsPerHost maximum number of connections per host.
* @param maxRequestsPerConnection maximum number of requests per connection.
* @param newConnectionThreshold threshold that triggers the creation of a new connection to a host.
*/
static LocalHostDistancePoolingOptions create(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost,
Integer maxRequestsPerConnection, Integer newConnectionThreshold) {
return new LocalHostDistancePoolingOptions(coreConnectionsPerHost, maxConnectionsPerHost,
maxRequestsPerConnection, newConnectionThreshold);
}
/**
* Constructs an instance of {@link LocalHostDistancePoolingOptions} initialized with {@link PoolingOptions} based
* on {@link HostDistance#LOCAL}.
@@ -636,8 +628,8 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* @param maxRequestsPerConnection maximum number of requests per connection.
* @param newConnectionThreshold threshold that triggers the creation of a new connection to a host.
*/
LocalHostDistancePoolingOptions(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost,
Integer maxRequestsPerConnection, Integer newConnectionThreshold) {
LocalHostDistancePoolingOptions(@Nullable Integer coreConnectionsPerHost, @Nullable Integer maxConnectionsPerHost,
@Nullable Integer maxRequestsPerConnection, @Nullable Integer newConnectionThreshold) {
super(coreConnectionsPerHost, maxConnectionsPerHost, maxRequestsPerConnection, newConnectionThreshold);
}
@@ -662,22 +654,6 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
*/
static class RemoteHostDistancePoolingOptions extends HostDistancePoolingOptions {
/**
* Creates an instance of {@link RemoteHostDistancePoolingOptions} initialized with {@link PoolingOptions} based on
* {@link HostDistance#REMOTE}.
*
* @param coreConnectionsPerHost core number of connections per host.
* @param maxConnectionsPerHost maximum number of connections per host.
* @param maxRequestsPerConnection maximum number of requests per connection.
* @param newConnectionThreshold threshold that triggers the creation of a new connection to a host.
*/
static RemoteHostDistancePoolingOptions create(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost,
Integer maxRequestsPerConnection, Integer newConnectionThreshold) {
return new RemoteHostDistancePoolingOptions(coreConnectionsPerHost, maxConnectionsPerHost,
maxRequestsPerConnection, newConnectionThreshold);
}
/**
* Constructs an instance of {@link RemoteHostDistancePoolingOptions} initialized with {@link PoolingOptions} based
* on {@link HostDistance#REMOTE}.
@@ -687,8 +663,8 @@ public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, I
* @param maxRequestsPerConnection maximum number of requests per connection.
* @param newConnectionThreshold threshold that triggers the creation of a new connection to a host.
*/
RemoteHostDistancePoolingOptions(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost,
Integer maxRequestsPerConnection, Integer newConnectionThreshold) {
RemoteHostDistancePoolingOptions(@Nullable Integer coreConnectionsPerHost, @Nullable Integer maxConnectionsPerHost,
@Nullable Integer maxRequestsPerConnection, @Nullable Integer newConnectionThreshold) {
super(coreConnectionsPerHost, maxConnectionsPerHost, maxRequestsPerConnection, newConnectionThreshold);
}

View File

@@ -48,21 +48,4 @@ public enum SchemaAction {
* Drop <em>all</em> tables in the keyspace, then create each table as necessary.
*/
RECREATE_DROP_UNUSED
// TODO:
// /**
// * Alter or create each table and column as necessary, leaving unused tables and columns untouched.
// */
// UPDATE,
//
// /**
// * Alter or create each table and column as necessary, removing unused tables and columns.
// */
// UPDATE_DROP_UNUNSED,
//
// /**
// * Validate that each required table and column exists. Fail if any required table or column does not exists.
// */
// VALIDATE
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.config;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.SocketOptions;
@@ -27,18 +28,19 @@ import com.datastax.driver.core.SocketOptions;
* @author Matthew T. Adams
* @author David Webb
*/
@SuppressWarnings({ "unused", "WeakerAccess" })
public class SocketOptionsFactoryBean implements FactoryBean<SocketOptions>, InitializingBean, DisposableBean {
private Integer connectTimeoutMillis;
private Boolean keepAlive;
private Integer readTimeoutMillis;
private Boolean reuseAddress;
private Integer soLinger;
private Boolean tcpNoDelay;
private Integer receiveBufferSize;
private Integer sendBufferSize;
private @Nullable Integer connectTimeoutMillis;
private @Nullable Boolean keepAlive;
private @Nullable Integer readTimeoutMillis;
private @Nullable Boolean reuseAddress;
private @Nullable Integer soLinger;
private @Nullable Boolean tcpNoDelay;
private @Nullable Integer receiveBufferSize;
private @Nullable Integer sendBufferSize;
private SocketOptions socketOptions;
private @Nullable SocketOptions socketOptions;
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
@@ -122,57 +124,64 @@ public class SocketOptionsFactoryBean implements FactoryBean<SocketOptions>, Ini
return true;
}
@Nullable
public Boolean getKeepAlive() {
return keepAlive;
}
public void setKeepAlive(Boolean keepAlive) {
public void setKeepAlive(@Nullable Boolean keepAlive) {
this.keepAlive = keepAlive;
}
@Nullable
public Boolean getReuseAddress() {
return reuseAddress;
}
public void setReuseAddress(Boolean reuseAddress) {
public void setReuseAddress(@Nullable Boolean reuseAddress) {
this.reuseAddress = reuseAddress;
}
@Nullable
public Integer getSoLinger() {
return soLinger;
}
public void setSoLinger(Integer soLinger) {
public void setSoLinger(@Nullable Integer soLinger) {
this.soLinger = soLinger;
}
@Nullable
public Boolean getTcpNoDelay() {
return tcpNoDelay;
}
public void setTcpNoDelay(Boolean tcpNoDelay) {
public void setTcpNoDelay(@Nullable Boolean tcpNoDelay) {
this.tcpNoDelay = tcpNoDelay;
}
@Nullable
public Integer getReceiveBufferSize() {
return receiveBufferSize;
}
public void setReceiveBufferSize(Integer receiveBufferSize) {
public void setReceiveBufferSize(@Nullable Integer receiveBufferSize) {
this.receiveBufferSize = receiveBufferSize;
}
@Nullable
public Integer getSendBufferSize() {
return sendBufferSize;
}
public void setSendBufferSize(Integer sendBufferSize) {
public void setSendBufferSize(@Nullable Integer sendBufferSize) {
this.sendBufferSize = sendBufferSize;
}
/**
* @return Returns the connectTimeoutMillis.
*/
@Nullable
public Integer getConnectTimeoutMillis() {
return connectTimeoutMillis;
}
@@ -180,13 +189,14 @@ public class SocketOptionsFactoryBean implements FactoryBean<SocketOptions>, Ini
/**
* @param connectTimeoutMillis The connectTimeoutMillis to set.
*/
public void setConnectTimeoutMillis(Integer connectTimeoutMillis) {
public void setConnectTimeoutMillis(@Nullable Integer connectTimeoutMillis) {
this.connectTimeoutMillis = connectTimeoutMillis;
}
/**
* @return Returns the readTimeoutMillis.
*/
@Nullable
public Integer getReadTimeoutMillis() {
return readTimeoutMillis;
}
@@ -194,7 +204,7 @@ public class SocketOptionsFactoryBean implements FactoryBean<SocketOptions>, Ini
/**
* @param readTimeoutMillis The readTimeoutMillis to set.
*/
public void setReadTimeoutMillis(Integer readTimeoutMillis) {
public void setReadTimeoutMillis(@Nullable Integer readTimeoutMillis) {
this.readTimeoutMillis = readTimeoutMillis;
}

View File

@@ -1,4 +1,7 @@
/**
* Spring Data Cassandra {@link org.springframework.beans.factory.FactoryBean factory beans} and configuration.
*/
@NonNullApi
package org.springframework.data.cassandra.config;
import org.springframework.lang.NonNullApi;

View File

@@ -240,9 +240,10 @@ public interface AsyncCassandraOperations {
* Insert the given entity applying {@link WriteOptions} and return the entity if the insert was applied.
*
* @param entity The entity to insert, must not be {@literal null}.
* @param options may be {@literal null}.
* @param options must not be {@literal null}.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
* @see InsertOptions#empty()
*/
ListenableFuture<WriteResult> insert(Object entity, InsertOptions options) throws DataAccessException;
@@ -259,9 +260,10 @@ public interface AsyncCassandraOperations {
* Update the given entity applying {@link WriteOptions} and return the entity if the update was applied.
*
* @param entity The entity to update, must not be {@literal null}.
* @param options may be {@literal null}.
* @param options must not be {@literal null}.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
* @see UpdateOptions#empty()
*/
ListenableFuture<WriteResult> update(Object entity, UpdateOptions options) throws DataAccessException;
@@ -278,9 +280,10 @@ public interface AsyncCassandraOperations {
* Delete the given entity applying {@link QueryOptions} and return the entity if the delete was applied.
*
* @param entity must not be {@literal null}.
* @param options may be {@literal null}.
* @param options must not be {@literal null}.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
* @see QueryOptions#empty()
*/
ListenableFuture<WriteResult> delete(Object entity, QueryOptions options) throws DataAccessException;
@@ -303,5 +306,4 @@ public interface AsyncCassandraOperations {
* @throws DataAccessException if there is any problem executing the query.
*/
ListenableFuture<Void> truncate(Class<?> entityClass) throws DataAccessException;
}

View File

@@ -40,6 +40,7 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.core.query.Query;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.concurrent.ListenableFuture;
@@ -417,7 +418,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
*/
@Override
public <T> ListenableFuture<T> insert(T entity) {
return new MappingListenableFutureAdapter<>(insert(entity, null), writeResult -> entity);
return new MappingListenableFutureAdapter<>(insert(entity, InsertOptions.empty()), writeResult -> entity);
}
/*
@@ -428,6 +429,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
public ListenableFuture<WriteResult> insert(Object entity, InsertOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "InsertOptions must not be null");
Insert insert = QueryUtils.createInsertQuery(getTableName(entity).toCql(), entity, options, getConverter());
@@ -441,7 +443,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
*/
@Override
public <T> ListenableFuture<T> update(T entity) {
return new MappingListenableFutureAdapter<>(update(entity, null), writeResult -> entity);
return new MappingListenableFutureAdapter<>(update(entity, UpdateOptions.empty()), writeResult -> entity);
}
/*
@@ -452,6 +454,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
public ListenableFuture<WriteResult> update(Object entity, UpdateOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "UpdateOptions must not be null");
Update update = QueryUtils.createUpdateQuery(getTableName(entity).toCql(), entity, options, getConverter());
@@ -465,7 +468,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
*/
@Override
public <T> ListenableFuture<T> delete(T entity) {
return new MappingListenableFutureAdapter<>(delete(entity, null), writeResult -> entity);
return new MappingListenableFutureAdapter<>(delete(entity, QueryOptions.empty()), writeResult -> entity);
}
/*
@@ -476,6 +479,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
public ListenableFuture<WriteResult> delete(Object entity, QueryOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "QueryOptions must not be null");
Delete delete = QueryUtils.createDeleteQuery(getTableName(entity).toCql(), entity, options, getConverter());
@@ -528,7 +532,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
}
@Override
protected T adapt(S adapteeResult) throws ExecutionException {
protected T adapt(@Nullable S adapteeResult) throws ExecutionException {
return mapper.apply(adapteeResult);
}
}

View File

@@ -78,5 +78,4 @@ public interface CassandraAdminOperations extends CassandraOperations {
* @since 1.5
*/
void dropUserType(CqlIdentifier typeName);
}

View File

@@ -126,6 +126,7 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
@Override
public KeyspaceMetadata getKeyspaceMetadata() {
// noinspection ConstantConditions
return getCqlOperations().execute((SessionCallback<KeyspaceMetadata>) session -> {
KeyspaceMetadata keyspaceMetadata = session.getCluster().getMetadata().getKeyspace(session.getLoggedKeyspace());

View File

@@ -129,5 +129,4 @@ public interface CassandraBatchOperations {
* @throws IllegalStateException if the batch was already executed.
*/
CassandraBatchOperations delete(Iterable<?> entities);
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import org.springframework.data.cassandra.core.cql.QueryOptions;
import org.springframework.data.cassandra.core.cql.WriteOptions;
import org.springframework.util.Assert;
@@ -34,8 +35,6 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
*/
class CassandraBatchTemplate implements CassandraBatchOperations {
private static final WriteOptions EMPTY = new WriteOptions();
private AtomicBoolean executed = new AtomicBoolean();
private final Batch batch;
@@ -47,7 +46,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
*
* @param operations must not be {@literal null}.
*/
public CassandraBatchTemplate(CassandraOperations operations) {
CassandraBatchTemplate(CassandraOperations operations) {
Assert.notNull(operations, "CassandraOperations must not be null");
@@ -65,9 +64,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
return WriteResult.of(operations.getCqlOperations().queryForResultSet(batch));
}
assertNotExecuted();
return null; // code won't reach this line
throw new IllegalStateException("This Cassandra Batch was already executed");
}
/* (non-Javadoc)
@@ -99,7 +96,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
*/
@Override
public CassandraBatchOperations insert(Iterable<?> entities) {
return insert(entities, EMPTY);
return insert(entities, InsertOptions.empty());
}
/* (non-Javadoc)
@@ -137,7 +134,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
*/
@Override
public CassandraBatchOperations update(Iterable<?> entities) {
return update(entities, EMPTY);
return update(entities, UpdateOptions.empty());
}
/* (non-Javadoc)
@@ -181,7 +178,8 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
for (Object entity : entities) {
Assert.notNull(entity, "Entity must not be null");
batch.add(QueryUtils.createDeleteQuery(getTableName(entity), entity, null, operations.getConverter()));
batch.add(
QueryUtils.createDeleteQuery(getTableName(entity), entity, QueryOptions.empty(), operations.getConverter()));
}
return this;

View File

@@ -27,6 +27,7 @@ import org.springframework.data.cassandra.core.cql.QueryOptions;
import org.springframework.data.cassandra.core.cql.WriteOptions;
import org.springframework.data.cassandra.core.query.Query;
import org.springframework.data.cassandra.core.query.Update;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.Statement;
@@ -113,6 +114,7 @@ public interface CassandraOperations {
* @return the converted object or {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
*/
@Nullable
<T> T selectOne(String cql, Class<T> entityClass) throws DataAccessException;
// -------------------------------------------------------------------------
@@ -151,6 +153,7 @@ public interface CassandraOperations {
* @return the converted object or {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
*/
@Nullable
<T> T selectOne(Statement statement, Class<T> entityClass) throws DataAccessException;
// -------------------------------------------------------------------------
@@ -190,6 +193,7 @@ public interface CassandraOperations {
* @throws DataAccessException if there is any problem executing the query.
* @since 2.0
*/
@Nullable
<T> T selectOne(Query query, Class<T> entityClass) throws DataAccessException;
/**
@@ -246,6 +250,7 @@ public interface CassandraOperations {
* @return the converted object or {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
*/
@Nullable
<T> T selectOneById(Object id, Class<T> entityClass) throws DataAccessException;
/**
@@ -260,9 +265,10 @@ public interface CassandraOperations {
* Insert the given entity applying {@link WriteOptions} and return the entity if the insert was applied.
*
* @param entity The entity to insert, must not be {@literal null}.
* @param options may be {@literal null}.
* @param options must not be {@literal null}.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
* @see InsertOptions#empty()
*/
WriteResult insert(Object entity, InsertOptions options) throws DataAccessException;
@@ -278,9 +284,10 @@ public interface CassandraOperations {
* Update the given entity applying {@link WriteOptions} and return the entity if the update was applied.
*
* @param entity The entity to update, must not be {@literal null}.
* @param options may be {@literal null}.
* @param options must not be {@literal null}.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
* @see UpdateOptions#empty()
*/
WriteResult update(Object entity, UpdateOptions options) throws DataAccessException;
@@ -296,9 +303,10 @@ public interface CassandraOperations {
* Delete the given entity applying {@link QueryOptions} and return the entity if the delete was applied.
*
* @param entity must not be {@literal null}.
* @param options may be {@literal null}.
* @param options must not be {@literal null}.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
* @see QueryOptions#empty()
*/
WriteResult delete(Object entity, QueryOptions options) throws DataAccessException;
@@ -320,5 +328,4 @@ public interface CassandraOperations {
* @throws DataAccessException if there is any problem executing the query.
*/
void truncate(Class<?> entityClass) throws DataAccessException;
}

View File

@@ -18,10 +18,7 @@ package org.springframework.data.cassandra.core;
import lombok.NonNull;
import lombok.Value;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -286,8 +283,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return select(getStatementFactory().select(query,
getMappingContext().getRequiredPersistentEntity(entityClass)), entityClass);
return select(getStatementFactory().select(query, getMappingContext().getRequiredPersistentEntity(entityClass)),
entityClass);
}
/* (non-Javadoc)
@@ -299,8 +296,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return stream(getStatementFactory().select(query,
getMappingContext().getRequiredPersistentEntity(entityClass)), entityClass);
return stream(getStatementFactory().select(query, getMappingContext().getRequiredPersistentEntity(entityClass)),
entityClass);
}
/* (non-Javadoc)
@@ -325,8 +322,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(update, "Update must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return getCqlOperations().execute(getStatementFactory().update(query, update,
getMappingContext().getRequiredPersistentEntity(entityClass)));
return getCqlOperations().execute(
getStatementFactory().update(query, update, getMappingContext().getRequiredPersistentEntity(entityClass)));
}
/* (non-Javadoc)
@@ -338,8 +335,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return getCqlOperations().execute(getStatementFactory().delete(query,
getMappingContext().getRequiredPersistentEntity(entityClass)));
return getCqlOperations()
.execute(getStatementFactory().delete(query, getMappingContext().getRequiredPersistentEntity(entityClass)));
}
// -------------------------------------------------------------------------
@@ -358,7 +355,9 @@ public class CassandraTemplate implements CassandraOperations {
Select select = QueryBuilder.select().countAll()
.from(getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql());
return getCqlOperations().queryForObject(select, Long.class);
Long count = getCqlOperations().queryForObject(select, Long.class);
return count != null ? count : 0L;
}
/*
@@ -405,7 +404,7 @@ public class CassandraTemplate implements CassandraOperations {
*/
@Override
public void insert(Object entity) {
insert(entity, null);
insert(entity, InsertOptions.empty());
}
/*
@@ -416,10 +415,11 @@ public class CassandraTemplate implements CassandraOperations {
public WriteResult insert(Object entity, InsertOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "InsertOptions must not be null");
Insert insert = QueryUtils.createInsertQuery(
getTableName(entity.getClass()).toCql(), entity, options, converter);
Insert insert = QueryUtils.createInsertQuery(getTableName(entity.getClass()).toCql(), entity, options, converter);
// noinspection ConstantConditions
return getCqlOperations().execute(new StatementCallback(insert));
}
@@ -429,7 +429,7 @@ public class CassandraTemplate implements CassandraOperations {
*/
@Override
public void update(Object entity) {
update(entity, null);
update(entity, UpdateOptions.empty());
}
/*
@@ -440,10 +440,11 @@ public class CassandraTemplate implements CassandraOperations {
public WriteResult update(Object entity, UpdateOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "UpdateOptions must not be null");
Update update = QueryUtils.createUpdateQuery(
getTableName(entity.getClass()).toCql(), entity, options, converter);
Update update = QueryUtils.createUpdateQuery(getTableName(entity.getClass()).toCql(), entity, options, converter);
// noinspection ConstantConditions
return getCqlOperations().execute(new StatementCallback(update));
}
@@ -453,7 +454,7 @@ public class CassandraTemplate implements CassandraOperations {
*/
@Override
public void delete(Object entity) {
delete(entity, null);
delete(entity, QueryOptions.empty());
}
/*
@@ -464,10 +465,11 @@ public class CassandraTemplate implements CassandraOperations {
public WriteResult delete(Object entity, QueryOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "QueryOptions must not be null");
Delete delete = QueryUtils.createDeleteQuery(
getTableName(entity.getClass()).toCql(), entity, options, converter);
Delete delete = QueryUtils.createDeleteQuery(getTableName(entity.getClass()).toCql(), entity, options, converter);
// noinspection ConstantConditions
return getCqlOperations().execute(new StatementCallback(delete));
}
@@ -499,8 +501,8 @@ public class CassandraTemplate implements CassandraOperations {
Assert.notNull(entityClass, "Entity type must not be null");
Truncate truncate = QueryBuilder.truncate(
getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql());
Truncate truncate = QueryBuilder
.truncate(getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql());
getCqlOperations().execute(truncate);
}
@@ -528,19 +530,6 @@ public class CassandraTemplate implements CassandraOperations {
return new CassandraBatchTemplate(this);
}
private <T> List<T> toList(Iterable<T> iterable) {
if (iterable instanceof List) {
return (List<T>) iterable;
}
if (iterable instanceof Collection) {
return new ArrayList<>((Collection<T>) iterable);
}
return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
}
@Value
static class StatementCallback implements SessionCallback<WriteResult>, CqlProvider {

View File

@@ -15,9 +15,14 @@
*/
package org.springframework.data.cassandra.core;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.springframework.data.cassandra.core.cql.WriteOptions;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.policies.RetryPolicy;
/**
* Extension to {@link WriteOptions} for use with {@code INSERT} operations.
@@ -27,12 +32,26 @@ import org.springframework.data.cassandra.core.cql.WriteOptions;
*/
public class InsertOptions extends WriteOptions {
private static final InsertOptions EMPTY = new InsertOptionsBuilder().build();
private boolean ifNotExists;
private InsertOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl, boolean ifNotExists) {
super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl);
this.ifNotExists = ifNotExists;
}
/**
* Creates new {@link InsertOptions}.
* Create default {@link InsertOptions}.
*
* @return default {@link InsertOptions}.
* @since 2.0
*/
InsertOptions() {}
public static InsertOptions empty() {
return EMPTY;
}
/**
* Create a new {@link InsertOptionsBuilder}.
@@ -62,73 +81,52 @@ public class InsertOptions extends WriteOptions {
private InsertOptionsBuilder() {}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#consistencyLevel(com.datastax.driver.core.ConsistencyLevel)
*/
@Override
public InsertOptionsBuilder consistencyLevel(com.datastax.driver.core.ConsistencyLevel consistencyLevel) {
return (InsertOptionsBuilder) super.consistencyLevel(consistencyLevel);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#retryPolicy(org.springframework.data.cassandra.core.cql.RetryPolicy)
*/
@Override
public InsertOptionsBuilder retryPolicy(com.datastax.driver.core.policies.RetryPolicy driverRetryPolicy) {
return (InsertOptionsBuilder) super.retryPolicy(driverRetryPolicy);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#fetchSize(int)
*/
@Override
public InsertOptionsBuilder fetchSize(int fetchSize) {
return (InsertOptionsBuilder) super.fetchSize(fetchSize);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long)
*/
@Override
public InsertOptionsBuilder readTimeout(long readTimeout) {
return (InsertOptionsBuilder) super.readTimeout(readTimeout);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long, java.util.concurrent.TimeUnit)
*/
@Override
@Deprecated
public InsertOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) {
return (InsertOptionsBuilder) super.readTimeout(readTimeout, timeUnit);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#tracing(boolean)
*/
@Override
public InsertOptionsBuilder readTimeout(Duration readTimeout) {
return (InsertOptionsBuilder) super.readTimeout(readTimeout);
}
@Override
public InsertOptionsBuilder ttl(Duration ttl) {
return (InsertOptionsBuilder) super.ttl(ttl);
}
@Override
public InsertOptionsBuilder tracing(boolean tracing) {
return (InsertOptionsBuilder) super.tracing(tracing);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#withTracing()
*/
@Override
public InsertOptionsBuilder withTracing() {
return (InsertOptionsBuilder) super.withTracing();
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#ttl(int)
*/
public InsertOptionsBuilder ttl(int ttl) {
return (InsertOptionsBuilder) super.ttl(ttl);
}
@@ -161,12 +159,7 @@ public class InsertOptions extends WriteOptions {
* @return a new {@link InsertOptions} with the configured values
*/
public InsertOptions build() {
InsertOptions insertOptions = applyOptions(new InsertOptions());
insertOptions.ifNotExists = this.ifNotExists;
return insertOptions;
return new InsertOptions(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl, ifNotExists);
}
}
}

View File

@@ -46,7 +46,7 @@ class QueryUtils {
* @param entityWriter the {@link EntityWriter} to write insert values.
* @return The Query object to run with session.execute();
*/
public static Insert createInsertQuery(String tableName, Object objectToUpdate, WriteOptions options,
static Insert createInsertQuery(String tableName, Object objectToUpdate, WriteOptions options,
EntityWriter<Object, Object> entityWriter) {
Assert.hasText(tableName, "TableName must not be empty");
@@ -75,11 +75,11 @@ class QueryUtils {
*
* @param tableName the table name, must not be empty and not {@literal null}.
* @param objectToUpdate the object to update, must not be {@literal null}.
* @param options optional {@link WriteOptions} to apply to the {@link Update} statement, may be {@literal null}.
* @param options optional {@link WriteOptions} to apply to the {@link Update} statement.
* @param entityWriter the {@link EntityWriter} to write update assignments and where clauses.
* @return The Query object to run with session.execute();
*/
public static Update createUpdateQuery(String tableName, Object objectToUpdate, WriteOptions options,
static Update createUpdateQuery(String tableName, Object objectToUpdate, WriteOptions options,
EntityWriter<Object, Object> entityWriter) {
Assert.hasText(tableName, "TableName must not be empty");
@@ -108,11 +108,11 @@ class QueryUtils {
*
* @param tableName the table name, must not be empty and not {@literal null}.
* @param objectToDelete the object to delete, must not be {@literal null}.
* @param options optional {@link QueryOptions} to apply to the {@link Delete} statement, may be {@literal null}.
* @param options optional {@link QueryOptions} to apply to the {@link Delete} statement.
* @param entityWriter the {@link EntityWriter} to write delete where clauses.
* @return The Query object to run with session.execute();
*/
public static Delete createDeleteQuery(String tableName, Object objectToDelete, QueryOptions options,
static Delete createDeleteQuery(String tableName, Object objectToDelete, QueryOptions options,
EntityWriter<Object, Object> entityWriter) {
Assert.hasText(tableName, "TableName must not be empty");

View File

@@ -186,9 +186,10 @@ public interface ReactiveCassandraOperations {
* Insert the given entity applying {@link WriteOptions} and emit the entity if the insert was applied.
*
* @param entity The entity to insert, must not be {@literal null}.
* @param options may be {@literal null}.
* @param options must not be {@literal null}.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem issuing the execution.
* @see InsertOptions#empty()
*/
Mono<WriteResult> insert(Object entity, InsertOptions options) throws DataAccessException;
@@ -205,9 +206,10 @@ public interface ReactiveCassandraOperations {
* Update the given entity applying {@link WriteOptions} and emit the entity if the update was applied.
*
* @param entity The entity to update, must not be {@literal null}.
* @param options may be {@literal null}.
* @param options must not be {@literal null}.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem issuing the execution.
* @see UpdateOptions#empty()
*/
Mono<WriteResult> update(Object entity, UpdateOptions options) throws DataAccessException;
@@ -224,9 +226,10 @@ public interface ReactiveCassandraOperations {
* Delete the given entity applying {@link QueryOptions} and emit the entity if the delete was applied.
*
* @param entity must not be {@literal null}.
* @param options may be {@literal null}.
* @param options must not be {@literal null}.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem issuing the execution.
* @see QueryOptions#empty()
*/
Mono<WriteResult> delete(Object entity, QueryOptions options) throws DataAccessException;
@@ -264,5 +267,4 @@ public interface ReactiveCassandraOperations {
* @see ReactiveCqlOperations
*/
ReactiveCqlOperations getReactiveCqlOperations();
}

View File

@@ -17,10 +17,10 @@ package org.springframework.data.cassandra.core;
import lombok.NonNull;
import lombok.Value;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.reactivestreams.Publisher;
import org.springframework.dao.DataAccessException;
import org.springframework.data.cassandra.ReactiveResultSet;
import org.springframework.data.cassandra.ReactiveSession;
@@ -44,8 +44,6 @@ import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.reactivestreams.Publisher;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.SimpleStatement;
import com.datastax.driver.core.Statement;
@@ -378,7 +376,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
*/
@Override
public <T> Mono<T> insert(T entity) {
return insert(entity, null).map(writeResult -> entity);
return insert(entity, InsertOptions.empty()).map(writeResult -> entity);
}
/*
@@ -389,6 +387,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
public Mono<WriteResult> insert(Object entity, InsertOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "InsertOptions must not be null");
Insert insert = QueryUtils.createInsertQuery(getTableName(entity).toCql(), entity, options, getConverter());
@@ -401,7 +400,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
*/
@Override
public <T> Mono<T> update(T entity) {
return update(entity, null).map(writeResult -> entity);
return update(entity, UpdateOptions.empty()).map(writeResult -> entity);
}
/*
@@ -412,6 +411,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
public Mono<WriteResult> update(Object entity, UpdateOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "UpdateOptions must not be null");
Update update = QueryUtils.createUpdateQuery(getTableName(entity).toCql(), entity, options, converter);
@@ -424,7 +424,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
*/
@Override
public <T> Mono<T> delete(T entity) {
return delete(entity, null).map(reactiveWriteResult -> entity);
return delete(entity, QueryOptions.empty()).map(reactiveWriteResult -> entity);
}
/*
@@ -435,6 +435,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
public Mono<WriteResult> delete(Object entity, QueryOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "QueryOptions must not be null");
Delete delete = QueryUtils.createDeleteQuery(getTableName(entity).toCql(), entity, options, getConverter());

View File

@@ -140,8 +140,8 @@ public class StatementFactory {
List<Selector> selectors = getQueryMapper().getMappedSelectors(query.getColumns(), entity);
Sort sort = Optional.ofNullable(query.getSort()).map(querySort -> getQueryMapper().getMappedSort(querySort, entity))
.orElse(null);
Sort sort = Optional.of(query.getSort()).map(querySort -> getQueryMapper().getMappedSort(querySort, entity))
.orElse(Sort.unsorted());
Select select = select(selectors, entity.getTableName(), filter, sort);
@@ -178,7 +178,7 @@ public class StatementFactory {
select.where(toClause(criteriaDefinition));
}
if (sort != null) {
if (sort.isSorted()) {
List<Ordering> orderings = new ArrayList<>();
for (Order order : sort) {
@@ -412,7 +412,7 @@ public class StatementFactory {
return QueryBuilder.in(columnName, (List<?>) predicate.getValue());
}
if (predicate.getValue().getClass().isArray()) {
if (predicate.getValue() != null && predicate.getValue().getClass().isArray()) {
return QueryBuilder.in(columnName, (Object[]) predicate.getValue());
}
@@ -422,9 +422,13 @@ public class StatementFactory {
return QueryBuilder.like(columnName, predicate.getValue());
case "CONTAINS":
Assert.state(predicate.getValue() != null,
() -> String.format("CONTAINS value for column %s is null", columnName));
return QueryBuilder.contains(columnName, predicate.getValue());
case "CONTAINS KEY":
Assert.state(predicate.getValue() != null,
() -> String.format("CONTAINS KEY value for column %s is null", columnName));
return QueryBuilder.containsKey(columnName, predicate.getValue());
}

View File

@@ -15,9 +15,14 @@
*/
package org.springframework.data.cassandra.core;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.springframework.data.cassandra.core.cql.WriteOptions;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.policies.RetryPolicy;
/**
* Extension to {@link WriteOptions} for use with {@code UPDATE} operations.
@@ -27,12 +32,26 @@ import org.springframework.data.cassandra.core.cql.WriteOptions;
*/
public class UpdateOptions extends WriteOptions {
private static final UpdateOptions EMPTY = new UpdateOptionsBuilder().build();
private boolean ifExists;
private UpdateOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl, boolean ifExists) {
super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl);
this.ifExists = ifExists;
}
/**
* Creates new {@link UpdateOptions}.
* Create default {@link UpdateOptions}.
*
* @return default {@link UpdateOptions}.
* @since 2.0
*/
UpdateOptions() {}
public static UpdateOptions empty() {
return EMPTY;
}
/**
* Create a new {@link UpdateOptionsBuilder}.
@@ -62,73 +81,52 @@ public class UpdateOptions extends WriteOptions {
private UpdateOptionsBuilder() {}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#consistencyLevel(com.datastax.driver.core.ConsistencyLevel)
*/
@Override
public UpdateOptionsBuilder consistencyLevel(com.datastax.driver.core.ConsistencyLevel consistencyLevel) {
return (UpdateOptionsBuilder) super.consistencyLevel(consistencyLevel);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#retryPolicy(org.springframework.data.cassandra.core.cql.RetryPolicy)
*/
@Override
public UpdateOptionsBuilder retryPolicy(com.datastax.driver.core.policies.RetryPolicy driverRetryPolicy) {
return (UpdateOptionsBuilder) super.retryPolicy(driverRetryPolicy);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#fetchSize(int)
*/
@Override
public UpdateOptionsBuilder fetchSize(int fetchSize) {
return (UpdateOptionsBuilder) super.fetchSize(fetchSize);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long)
*/
@Override
public UpdateOptionsBuilder readTimeout(long readTimeout) {
return (UpdateOptionsBuilder) super.readTimeout(readTimeout);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long, java.util.concurrent.TimeUnit)
*/
@Override
@Deprecated
public UpdateOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) {
return (UpdateOptionsBuilder) super.readTimeout(readTimeout, timeUnit);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#tracing(boolean)
*/
@Override
public UpdateOptionsBuilder readTimeout(Duration readTimeout) {
return (UpdateOptionsBuilder) super.readTimeout(readTimeout);
}
@Override
public UpdateOptionsBuilder ttl(Duration ttl) {
return (UpdateOptionsBuilder) super.ttl(ttl);
}
@Override
public UpdateOptionsBuilder tracing(boolean tracing) {
return (UpdateOptionsBuilder) super.tracing(tracing);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#withTracing()
*/
@Override
public UpdateOptionsBuilder withTracing() {
return (UpdateOptionsBuilder) super.withTracing();
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#ttl(int)
*/
public UpdateOptionsBuilder ttl(int ttl) {
return (UpdateOptionsBuilder) super.ttl(ttl);
}
@@ -161,12 +159,7 @@ public class UpdateOptions extends WriteOptions {
* @return a new {@link UpdateOptions} with the configured values
*/
public UpdateOptions build() {
UpdateOptions insertOptions = applyOptions(new UpdateOptions());
insertOptions.ifExists = this.ifExists;
return insertOptions;
return new UpdateOptions(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl, ifExists);
}
}
}

View File

@@ -35,7 +35,6 @@ import com.datastax.driver.core.Row;
public class WriteResult {
private final boolean wasApplied;
private final List<ExecutionInfo> executionInfo;
private final List<Row> rows;

View File

@@ -19,10 +19,10 @@ import java.util.Collections;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.EntityInstantiators;
import org.springframework.util.Assert;
/**
* Base class for {@link CassandraConverter} implementations. Sets up a {@link ConversionService} and populates basic
@@ -36,32 +36,36 @@ import org.springframework.data.convert.EntityInstantiators;
*/
public abstract class AbstractCassandraConverter implements CassandraConverter, InitializingBean {
protected final ConversionService conversionService;
private final ConversionService conversionService;
protected CustomConversions conversions = new CassandraCustomConversions(Collections.emptyList());
private CustomConversions conversions = new CassandraCustomConversions(Collections.emptyList());
protected EntityInstantiators instantiators = new EntityInstantiators();
EntityInstantiators instantiators = new EntityInstantiators();
/**
* Create a new {@link AbstractCassandraConverter} using the given {@link ConversionService}.
*/
public AbstractCassandraConverter(ConversionService conversionService) {
this.conversionService = conversionService == null ? new DefaultConversionService() : conversionService;
protected AbstractCassandraConverter(ConversionService conversionService) {
Assert.notNull(conversionService, "ConversionService must not be null");
this.conversionService = conversionService;
}
/**
* Registers {@link EntityInstantiators} to customize entity instantiation.
*
* @param instantiators
* @param instantiators must not be {@literal null}.
*/
public void setInstantiators(EntityInstantiators instantiators) {
this.instantiators = instantiators == null ? new EntityInstantiators() : instantiators;
Assert.notNull(instantiators, "EntityInstantiators must not be null");
this.instantiators = instantiators;
}
/**
* Registers the given custom conversions with the converter.
*
* @param conversions
*/
public void setCustomConversions(CustomConversions conversions) {
this.conversions = conversions;

View File

@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.convert;
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.Row;
@@ -55,6 +56,7 @@ public class BasicCassandraRowValueProvider implements CassandraRowValueProvider
/* (non-Javadoc)
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
*/
@Nullable
@Override
@SuppressWarnings("unchecked")
public <T> T getPropertyValue(CassandraPersistentProperty property) {

View File

@@ -22,6 +22,7 @@ import org.springframework.data.cassandra.core.mapping.MapId;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.EntityConverter;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
/**
* Central Cassandra specific converter interface from Object to Row.
@@ -61,6 +62,7 @@ public interface CassandraConverter
* @param entity must not be {@literal null}.
* @return
*/
@Nullable
Object getId(Object object, CassandraPersistentEntity<?> entity);
/**
@@ -76,7 +78,7 @@ public interface CassandraConverter
* Converts the given object into a value Cassandra will be able to store natively in a column.
*
* @param value {@link Object} to convert; must not be {@literal null}.
* @param typeInformation {@link TypeInformation} used to describe the object type; may be {@literal null}.
* @param typeInformation {@link TypeInformation} used to describe the object type; must not be {@literal null}.
* @return the result of the conversion.
* @since 1.5
*/
@@ -85,10 +87,9 @@ public interface CassandraConverter
/**
* Converts and writes a {@code source} object into a {@code sink} using the given {@link CassandraPersistentEntity}.
*
* @param source the source, may be {@literal null}.
* @param source the source, must not be {@literal null}.
* @param sink must not be {@literal null}.
* @param entity must not be {@literal null}.
*/
void write(Object source, Object sink, CassandraPersistentEntity<?> entity);
}

View File

@@ -140,7 +140,7 @@ abstract class CassandraConverters {
private final Class<T> targetType;
public RowToNumber(Class<T> targetType) {
RowToNumber(Class<T> targetType) {
this.targetType = targetType;
}

View File

@@ -38,6 +38,7 @@ public class CassandraCustomConversions extends org.springframework.data.convert
private static final List<Object> STORE_CONVERTERS;
static {
List<Object> converters = new ArrayList<>();
converters.addAll(CassandraConverters.getConvertersToRegister());

View File

@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.convert;
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.CodecRegistry;
@@ -61,6 +62,7 @@ public class CassandraUDTValueProvider implements CassandraValueProvider {
/* (non-Javadoc)
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
*/
@Nullable
@SuppressWarnings("unchecked")
public <T> T getPropertyValue(CassandraPersistentProperty property) {

View File

@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.convert;
import java.util.List;
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.CodecRegistry;
import com.datastax.driver.core.ColumnDefinitions;
@@ -40,6 +41,7 @@ public class ColumnReader {
private final CodecRegistry codecRegistry;
public ColumnReader(Row row) {
this.row = row;
this.columns = row.getColumnDefinitions();
this.codecRegistry = CodecRegistry.DEFAULT_INSTANCE;
@@ -48,6 +50,7 @@ public class ColumnReader {
/**
* Returns the row's column value.
*/
@Nullable
public Object get(CqlIdentifier name) {
return get(name.toCql());
}
@@ -55,6 +58,7 @@ public class ColumnReader {
/**
* Returns the row's column value.
*/
@Nullable
public Object get(String name) {
int indexOf = getColumnIndex(name);
return get(indexOf);
@@ -66,6 +70,7 @@ public class ColumnReader {
* @param index
* @return
*/
@Nullable
public Object get(int index) {
if (row.isNull(index)) {
@@ -89,6 +94,7 @@ public class ColumnReader {
return row.getObject(index);
}
@Nullable
public Object getCollection(int i, DataType type) {
List<DataType> collectionTypes = type.getTypeArguments();
@@ -131,6 +137,7 @@ public class ColumnReader {
*
* @throws ClassCastException if the value cannot be converted to the requested type.
*/
@Nullable
public <T> T get(CqlIdentifier name, Class<T> requestedType) {
return get(getColumnIndex(name.toCql()), requestedType);
}
@@ -140,6 +147,7 @@ public class ColumnReader {
*
* @throws ClassCastException if the value cannot be converted to the requested type.
*/
@Nullable
public <T> T get(String name, Class<T> requestedType) {
return get(columns.getIndexOf(name), requestedType);
}
@@ -149,6 +157,7 @@ public class ColumnReader {
*
* @throws ClassCastException if the value cannot be converted to the requested type.
*/
@Nullable
@SuppressWarnings("unchecked")
public <T> T get(int i, Class<T> requestedType) {

View File

@@ -51,6 +51,7 @@ import org.springframework.data.mapping.model.PersistentEntityParameterValueProv
import org.springframework.data.mapping.model.SpELContext;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -86,7 +87,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
private final CassandraMappingContext mappingContext;
private ClassLoader beanClassLoader;
private @Nullable ClassLoader beanClassLoader;
private SpELContext spELContext;
@@ -151,6 +152,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* @param row must not be {@literal null}.
* @return the converted valued.
*/
@Nullable
@SuppressWarnings("unchecked")
public <R> R readRow(Class<R> type, Row row) {
@@ -302,24 +304,22 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
@Override
public Object convertToColumnType(Object value, TypeInformation<?> typeInformation) {
Assert.notNull(value, "Value must not be null");
Assert.notNull(typeInformation, "TypeInformation must not be null");
if (value == null) {
return null;
}
// noinspection ConstantConditions
return value.getClass().isArray() ? value : getWriteValue(value, typeInformation);
}
@Override
public void write(Object source, Object sink) {
if (source != null) {
Class<?> beanClassLoaderClass = transformClassToBeanClassLoaderClass(source.getClass());
CassandraPersistentEntity<?> entity = getMappingContext().getRequiredPersistentEntity(beanClassLoaderClass);
Assert.notNull(source, "Value must not be null");
write(source, sink, entity);
}
Class<?> beanClassLoaderClass = transformClassToBeanClassLoaderClass(source.getClass());
CassandraPersistentEntity<?> entity = getMappingContext().getRequiredPersistentEntity(beanClassLoaderClass);
write(source, sink, entity);
}
@SuppressWarnings("unchecked")
@@ -335,9 +335,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
@SuppressWarnings("unchecked")
public void write(Object source, Object sink, CassandraPersistentEntity<?> entity) {
if (source == null) {
return;
}
Assert.notNull(source, "Value must not be null");
if (entity == null) {
throw new MappingException("No mapping metadata found for " + source.getClass());
@@ -360,11 +358,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
}
}
protected void writeInsertFromObject(final Object object, final Insert insert, CassandraPersistentEntity<?> entity) {
protected void writeInsertFromObject(Object object, Insert insert, CassandraPersistentEntity<?> entity) {
writeInsertFromWrapper(getConvertingAccessor(object, entity), insert, entity);
}
private void writeMapFromWrapper(final ConvertingPropertyAccessor accessor, final Map<String, Object> insert,
private void writeMapFromWrapper(ConvertingPropertyAccessor accessor, Map<String, Object> insert,
CassandraPersistentEntity<?> entity) {
for (CassandraPersistentProperty property : entity) {
@@ -381,6 +379,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
log.debug("Property is a compositeKey");
}
if (value == null) {
continue;
}
CassandraPersistentEntity<?> compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property);
writeMapFromWrapper(getConvertingAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
@@ -412,6 +414,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
log.debug("Property is a compositeKey");
}
if (value == null) {
continue;
}
CassandraPersistentEntity<?> compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property);
writeInsertFromWrapper(getConvertingAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
@@ -445,7 +451,12 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
CassandraPersistentEntity<?> compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property);
if (value == null) {
continue;
}
writeUpdateFromWrapper(getConvertingAccessor(value, compositePrimaryKey), update, compositePrimaryKey);
continue;
}
@@ -696,6 +707,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* @param accessor the property accessor
* @return the return value, may be {@literal null}.
*/
@Nullable
@SuppressWarnings("unchecked")
private <T> T getWriteValue(CassandraPersistentProperty property, ConvertingPropertyAccessor accessor) {
return (T) getWriteValue(accessor.getProperty(property, (Class<T>) getTargetType(property)),
@@ -710,8 +722,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* @param typeInformation the type information.
* @return the return value, may be {@literal null}.
*/
@Nullable
@SuppressWarnings("unchecked")
private Object getWriteValue(Object value, TypeInformation<?> typeInformation) {
private Object getWriteValue(@Nullable Object value, @Nullable TypeInformation<?> typeInformation) {
if (value == null) {
return null;
@@ -735,7 +748,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
TypeInformation<?> type = typeInformation != null ? typeInformation
: ClassTypeInformation.from((Class) value.getClass());
TypeInformation<?> actualType = type.getActualType();
TypeInformation<?> actualType = type.getRequiredActualType();
if (value instanceof Collection) {
@@ -771,7 +784,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* @see CassandraType
*/
@SuppressWarnings("unchecked")
private Object getPotentiallyConvertedSimpleValue(Object value, Class<?> requestedTargetType) {
@Nullable
private Object getPotentiallyConvertedSimpleValue(@Nullable Object value, @Nullable Class<?> requestedTargetType) {
if (value == null) {
return null;
@@ -800,8 +814,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* @param target must not be {@literal null}.
* @return the converted value.
*/
@Nullable
@SuppressWarnings({ "rawtypes", "unchecked" })
private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target) {
private Object getPotentiallyConvertedSimpleRead(@Nullable Object value, @Nullable Class<?> target) {
if (value == null || target == null || target.isAssignableFrom(value.getClass())) {
return value;
@@ -847,6 +862,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* @param property the property.
* @return the return value, may be {@literal null}.
*/
@Nullable
@SuppressWarnings("unchecked")
protected Object getReadValue(CassandraValueProvider row, CassandraPersistentProperty property) {
@@ -899,6 +915,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* @param sourceValue must not be {@literal null}.
* @return the converted {@link Collection} or array, will never be {@literal null}.
*/
@Nullable
@SuppressWarnings({ "rawtypes", "unchecked" })
private Object readCollectionOrArray(TypeInformation<?> targetType, Collection<?> sourceValue) {
@@ -917,7 +934,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return getPotentiallyConvertedSimpleRead(items, collectionType);
}
BasicCassandraPersistentEntity<?> entity = getMappingContext().getPersistentEntity(componentType);
BasicCassandraPersistentEntity<?> entity = getMappingContext().getPersistentEntity(rawComponentType);
if (entity != null && entity.isUserDefinedType()) {
@@ -961,7 +978,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
/* (non-Javadoc)
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
*/
@Nullable
@Override
@SuppressWarnings("unchecked")
public <T> T getPropertyValue(CassandraPersistentProperty property) {
return (T) getReadValue(parent, property);
}

View File

@@ -46,22 +46,18 @@ import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentPropertyPath;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Map {@link org.springframework.data.cassandra.core.query.Query} to CQL-specific data types.
*
* @author Mark Paluch
* @see org.springframework.data.cassandra.core.query.ColumnName
* @see org.springframework.data.cassandra.core.query.Columns
* @see org.springframework.data.cassandra.core.query.Criteria
* @see org.springframework.data.cassandra.core.query.Filter
* @see org.springframework.data.domain.Sort
* @see org.springframework.data.mapping.PersistentProperty
* @see org.springframework.data.mapping.PropertyPath
* @see org.springframework.data.mapping.context.MappingContext
* @see org.springframework.data.mapping.context.PersistentPropertyPath
* @see org.springframework.data.util.TypeInformation
* @see ColumnName
* @see Columns
* @see Criteria
* @see Filter
* @see Sort
* @since 2.0
*/
public class QueryMapper {
@@ -131,7 +127,7 @@ public class QueryMapper {
Object value = predicate.getValue();
TypeInformation<?> typeInformation = getTypeInformation(field, value);
Object mappedValue = getConverter().convertToColumnType(value, typeInformation);
Object mappedValue = value != null ? getConverter().convertToColumnType(value, typeInformation) : null;
Predicate mappedPredicate = new Predicate(predicate.getOperator(), mappedValue);
@@ -328,18 +324,13 @@ public class QueryMapper {
}
}
/**
* @param entity
* @param key
* @return
*/
protected Field createPropertyField(CassandraPersistentEntity<?> entity, ColumnName key) {
return Optional.ofNullable(entity).<Field> map(e -> new MetadataBackedField(key, e, getMappingContext()))
return Optional.of(entity).<Field> map(e -> new MetadataBackedField(key, e, getMappingContext()))
.orElseGet(() -> new Field(key));
}
@SuppressWarnings("unchecked")
TypeInformation<?> getTypeInformation(Field field, Object value) {
TypeInformation<?> getTypeInformation(Field field, @Nullable Object value) {
if (field.getProperty().isPresent()) {
return field.getProperty().get().getTypeInformation();
@@ -366,7 +357,7 @@ public class QueryMapper {
*
* @param name must not be {@literal null} or empty.
*/
public Field(ColumnName name) {
Field(ColumnName name) {
Assert.notNull(name, "Name must not be null!");
this.name = name;
}
@@ -385,8 +376,6 @@ public class QueryMapper {
* Returns the underlying {@link CassandraPersistentProperty} backing the field. For path traversals this will be
* the property that represents the value to handle. This means it'll be the leaf property for plain paths or the
* association property in case we refer to an association somewhere in the path.
*
* @return
*/
public Optional<CassandraPersistentProperty> getProperty() {
return Optional.empty();
@@ -394,8 +383,6 @@ public class QueryMapper {
/**
* Returns the key to be used in the mapped document eventually.
*
* @return
*/
public ColumnName getMappedKey() {
return name;
@@ -412,7 +399,7 @@ public class QueryMapper {
private final CassandraPersistentEntity<?> entity;
private final MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext;
private final Optional<PersistentPropertyPath<CassandraPersistentProperty>> path;
private final CassandraPersistentProperty property;
private final @Nullable CassandraPersistentProperty property;
private final Optional<CassandraPersistentProperty> optionalProperty;
/**
@@ -440,7 +427,7 @@ public class QueryMapper {
*/
public MetadataBackedField(ColumnName name, CassandraPersistentEntity<?> entity,
MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext,
CassandraPersistentProperty property) {
@Nullable CassandraPersistentProperty property) {
super(name);

View File

@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.convert;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.Row;
@@ -38,12 +39,16 @@ enum RowReaderPropertyAccessor implements PropertyAccessor {
}
@Override
public boolean canRead(EvaluationContext context, Object target, String name) {
return ((Row) target).getColumnDefinitions().contains(name);
public boolean canRead(EvaluationContext context, @Nullable Object target, String name) {
return target != null && ((Row) target).getColumnDefinitions().contains(name);
}
@Override
public TypedValue read(EvaluationContext context, Object target, String name) {
public TypedValue read(EvaluationContext context, @Nullable Object target, String name) {
if (target == null) {
return TypedValue.NULL;
}
Row row = (Row) target;
@@ -55,12 +60,12 @@ enum RowReaderPropertyAccessor implements PropertyAccessor {
}
@Override
public boolean canWrite(EvaluationContext context, Object target, String name) {
public boolean canWrite(EvaluationContext context, @Nullable Object target, String name) {
return false;
}
@Override
public void write(EvaluationContext context, Object target, String name, Object newValue) {
public void write(EvaluationContext context, @Nullable Object target, String name, @Nullable Object newValue) {
throw new UnsupportedOperationException();
}
}

View File

@@ -120,12 +120,13 @@ public class UpdateMapper extends QueryMapper {
Object rawValue = updateOp.getValue();
Object value = rawValue;
if (updateOp instanceof SetAtKeyOp) {
SetAtKeyOp op = (SetAtKeyOp) updateOp;
Assert.state(op.getValue() != null,
() -> String.format("SetAtKeyOp for %s attempts to set null", field.getProperty()));
Optional<? extends TypeInformation<?>> typeInformation = field.getProperty()
.map(PersistentProperty::getTypeInformation);
@@ -141,12 +142,15 @@ public class UpdateMapper extends QueryMapper {
return new SetAtKeyOp(field.getMappedKey(), mappedKey, mappedValue);
}
TypeInformation<?> typeInformation = getTypeInformation(field, value);
TypeInformation<?> typeInformation = getTypeInformation(field, rawValue);
if (updateOp instanceof SetAtIndexOp) {
SetAtIndexOp op = (SetAtIndexOp) updateOp;
Assert.state(op.getValue() != null,
() -> String.format("SetAtIndexOp for %s attempts to set null", field.getProperty()));
Object mappedValue = getConverter().convertToColumnType(op.getValue(), typeInformation);
return new SetAtIndexOp(field.getMappedKey(), op.getIndex(), mappedValue);
@@ -169,7 +173,7 @@ public class UpdateMapper extends QueryMapper {
}
}
Object mappedValue = getConverter().convertToColumnType(value, typeInformation);
Object mappedValue = rawValue == null ? null : getConverter().convertToColumnType(rawValue, typeInformation);
return new SetOp(field.getMappedKey(), mappedValue);
}

View File

@@ -1,4 +1,7 @@
/**
* Spring Data Cassandra specific converter infrastructure.
*/
@NonNullApi
package org.springframework.data.cassandra.core.convert;
import org.springframework.lang.NonNullApi;

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.cassandra.core.cql;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.exceptions.DriverException;
@@ -27,14 +29,14 @@ import com.datastax.driver.core.exceptions.DriverException;
*/
public class ArgumentPreparedStatementBinder implements PreparedStatementBinder {
private final Object[] args;
private final @Nullable Object[] args;
/**
* Create a new {@link ArgumentPreparedStatementBinder} for the given arguments.
*
* @param args the arguments to set. May be empty or {@link null} if no arguments are provided.
*/
public ArgumentPreparedStatementBinder(Object[] args) {
public ArgumentPreparedStatementBinder(@Nullable Object[] args) {
this.args = args;
}

View File

@@ -22,6 +22,7 @@ import java.util.Map;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.lang.Nullable;
import org.springframework.util.concurrent.ListenableFuture;
import com.datastax.driver.core.PreparedStatement;
@@ -42,9 +43,6 @@ import com.datastax.driver.core.Statement;
*/
public interface AsyncCqlOperations {
// TODO many of these data access operations could be implemented as default methods, in terms of other data access
// operations
// -------------------------------------------------------------------------
// Methods dealing with a plain com.datastax.driver.core.Session
// -------------------------------------------------------------------------
@@ -70,7 +68,7 @@ public interface AsyncCqlOperations {
/**
* Issue a single CQL execute, typically a DDL statement, insert, update or delete statement.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @return boolean value whether the statement was applied.
* @throws DataAccessException if there is any problem executing the query.
*/
@@ -80,7 +78,7 @@ public interface AsyncCqlOperations {
* Issue a single CQL operation (such as an insert, update or delete statement) via a prepared statement, binding the
* given arguments.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
* CQL type).
* @return boolean value whether the statement was applied.
@@ -93,14 +91,14 @@ public interface AsyncCqlOperations {
* using a {@link AsyncPreparedStatementCreator} as this method will create the {@link PreparedStatement}: The
* {@link PreparedStatementBinder} just needs to set parameters.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @return boolean value whether the statement was applied.
* @throws DataAccessException if there is any problem issuing the execution.
*/
ListenableFuture<Boolean> execute(String cql, PreparedStatementBinder preparedStatementBinder)
ListenableFuture<Boolean> execute(String cql, @Nullable PreparedStatementBinder psb)
throws DataAccessException;
/**
@@ -111,7 +109,7 @@ public interface AsyncCqlOperations {
* <p>
* The callback action can return a result object, for example a domain object or a collection of domain objects.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param action callback object that specifies the action, must not be {@literal null}.
* @return a result object returned by the action, or {@literal null}
* @throws DataAccessException if there is any problem TODO: Lambda-usage clashes with execute(cql,
@@ -125,7 +123,7 @@ public interface AsyncCqlOperations {
* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a
* {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param resultSetExtractor object that will extract all rows of results, must not be {@literal null}.
* @return an arbitrary result object, as returned by the ResultSetExtractor.
* @throws DataAccessException if there is any problem executing the query.
@@ -138,9 +136,9 @@ public interface AsyncCqlOperations {
* {@link RowCallbackHandler}.
* <p>
* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a
* {@link PreparedStatement}, use the overloaded {@code query} method with {@code null} as argument array.
* {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}.
* @throws DataAccessException if there is any problem executing the query
* @see #query(String, RowCallbackHandler, Object[])
@@ -153,7 +151,7 @@ public interface AsyncCqlOperations {
* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a
* {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param rowMapper object that will map one object per row, must not be {@literal null}.
* @return the result {@link List}, containing mapped objects.
* @throws DataAccessException if there is any problem executing the query
@@ -165,7 +163,7 @@ public interface AsyncCqlOperations {
* Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, reading the
* {@link ResultSet} with a {@link ResultSetExtractor}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param resultSetExtractor object that will extract results, must not be {@literal null}.
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
* CQL type).
@@ -179,7 +177,7 @@ public interface AsyncCqlOperations {
* Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, reading the
* {@link ResultSet} on a per-row basis with a {@link RowCallbackHandler}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}.
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
* CQL type)
@@ -192,7 +190,7 @@ public interface AsyncCqlOperations {
* Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, mapping each
* row to a Java object via a {@link RowMapper}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param rowMapper object that will map one object per row
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
* CQL type)
@@ -204,15 +202,15 @@ public interface AsyncCqlOperations {
/**
* Query using a prepared statement, reading the {@link ResultSet} with a {@link ResultSetExtractor}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param resultSetExtractor object that will extract results, must not be {@literal null}.
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}.
* @throws DataAccessException if there is any problem
*/
<T> ListenableFuture<T> query(String cql, PreparedStatementBinder preparedStatementBinder,
<T> ListenableFuture<T> query(String cql, @Nullable PreparedStatementBinder psb,
ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
/**
@@ -220,29 +218,29 @@ public interface AsyncCqlOperations {
* knows how to bind values to the query, reading the {@link ResultSet} on a per-row basis with a
* {@link RowCallbackHandler}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
*/
ListenableFuture<Void> query(String cql, PreparedStatementBinder preparedStatementBinder,
ListenableFuture<Void> query(String cql, @Nullable PreparedStatementBinder psb,
RowCallbackHandler rowCallbackHandler) throws DataAccessException;
/**
* Query given CQL to create a prepared statement from CQL and a {@link PreparedStatementBinder} implementation that
* knows how to bind values to the query, mapping each row to a Java object via a {@link RowMapper}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param rowMapper object that will map one object per row, must not be {@literal null}.
* @return the result {@link List}, containing mapped objects.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> ListenableFuture<List<T>> query(String cql, PreparedStatementBinder preparedStatementBinder,
<T> ListenableFuture<List<T>> query(String cql, @Nullable PreparedStatementBinder psb,
RowMapper<T> rowMapper) throws DataAccessException;
/**
@@ -255,7 +253,7 @@ public interface AsyncCqlOperations {
* using the column name as the key). Each item in the {@link List} will be of the form returned by this interface's
* queryForMap() methods.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @return a {@link List} that contains a {@link Map} per row.
* @throws DataAccessException if there is any problem executing the query.
* @see #queryForList(String, Object[])
@@ -270,7 +268,7 @@ public interface AsyncCqlOperations {
* using the column name as the key). Each item in the {@link List} will be of the form returned by this interface's
* queryForMap() methods.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
* CQL type).
* @return a {@link List} that contains a {@link Map} per row
@@ -288,7 +286,7 @@ public interface AsyncCqlOperations {
* The results will be mapped to a {@link List} (one item for each row) of result objects, each of them matching the
* specified element type.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param elementType the required type of element in the result {@link List} (for example, {@code Integer.class}),
* must not be {@literal null}.
* @return a {@link List} of objects that match the specified element type.
@@ -305,7 +303,7 @@ public interface AsyncCqlOperations {
* The results will be mapped to a {@link List} (one item for each row) of result objects, each of them matching the
* specified element type.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param elementType the required type of element in the result {@link List} (for example, {@code Integer.class}),
* must not be {@literal null}.
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
@@ -328,7 +326,7 @@ public interface AsyncCqlOperations {
* The query is expected to be a single row query; the result row will be mapped to a Map (one entry for each column,
* using the column name as the key).
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @return the result Map (one entry for each column, using the column name as the key), must not be {@literal null}.
* @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row.
* @throws DataAccessException if there is any problem executing the query.
@@ -345,7 +343,7 @@ public interface AsyncCqlOperations {
* The query is expected to be a single row query; the result row will be mapped to a Map (one entry for each column,
* using the column name as the key).
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
* CQL type).
* @return the result Map (one entry for each column, using the column name as the key).
@@ -366,7 +364,7 @@ public interface AsyncCqlOperations {
* This method is useful for running static CQL with a known outcome. The query is expected to be a single row/single
* column query; the returned result will be directly mapped to the corresponding object type.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param requiredType the type that the result object is expected to match, must not be {@literal null}.
* @return the result object of the required type, or {@link Mono#empty()} in case of CQL NULL.
* @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row, or does not return
@@ -383,7 +381,7 @@ public interface AsyncCqlOperations {
* The query is expected to be a single row/single column query; the returned result will be directly mapped to the
* corresponding object type.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param requiredType the type that the result object is expected to match, must not be {@literal null}.
* @param args arguments to bind to the query (leaving it to the PreparedStatement to guess the corresponding CQL
* type)
@@ -402,7 +400,7 @@ public interface AsyncCqlOperations {
* {@link PreparedStatement}, use the overloaded {@link #queryForObject(String, RowMapper, Object...)} method with
* {@literal null} as argument array.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param rowMapper object that will map one object per row, must not be {@literal null}.
* @return the single mapped object.
* @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row.
@@ -415,7 +413,7 @@ public interface AsyncCqlOperations {
* Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, mapping a
* single result row to a Java object via a {@link RowMapper}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param rowMapper object that will map one object per row, must not be {@literal null}.
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
* CQL type)
@@ -434,7 +432,7 @@ public interface AsyncCqlOperations {
* <p>
* The results will be mapped to an {@link ResultSet}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @return a {@link ResultSet} representation.
* @throws DataAccessException if there is any problem executing the query.
* @see #queryForResultSet(String, Object[])
@@ -447,7 +445,7 @@ public interface AsyncCqlOperations {
* <p>
* The results will be mapped to an {@link ResultSet}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param cql static CQL to execute, must not be {@literal null} or empty.
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
* CQL type).
* @return a {@link ResultSet} representation.
@@ -489,7 +487,7 @@ public interface AsyncCqlOperations {
* {@link RowCallbackHandler}.
* <p>
* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a
* {@link PreparedStatement}, use the overloaded {@code query} method with {@code null} as argument array.
* {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array.
*
* @param statement static CQL {@link Statement}, must not be {@literal null}.
* @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}.
@@ -522,7 +520,7 @@ public interface AsyncCqlOperations {
* using the column name as the key). Each item in the {@link List} will be of the form returned by this interface's
* queryForMap() methods.
*
* @param statement static CQL {@link Statement} to execute, must not be empty or {@literal null}.
* @param statement static CQL {@link Statement} to execute, must not be {@literal null} or empty.
* @return a {@link List} that contains a {@link Map} per row.
* @throws DataAccessException if there is any problem executing the query.
* @see #queryForList(String, Object[])
@@ -693,15 +691,15 @@ public interface AsyncCqlOperations {
*
* @param preparedStatementCreator object that can create a {@link PreparedStatement} given a
* {@link com.datastax.driver.core.Session}, must not be {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param resultSetExtractor object that will extract results, must not be {@literal null}.
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}.
* @throws DataAccessException if there is any problem
*/
<T> ListenableFuture<T> query(AsyncPreparedStatementCreator preparedStatementCreator,
PreparedStatementBinder preparedStatementBinder, ResultSetExtractor<T> resultSetExtractor)
@Nullable PreparedStatementBinder psb, ResultSetExtractor<T> resultSetExtractor)
throws DataAccessException;
/**
@@ -710,14 +708,14 @@ public interface AsyncCqlOperations {
*
* @param preparedStatementCreator object that can create a {@link PreparedStatement} given a
* {@link com.datastax.driver.core.Session}, must not be {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
*/
ListenableFuture<Void> query(AsyncPreparedStatementCreator preparedStatementCreator,
PreparedStatementBinder preparedStatementBinder, RowCallbackHandler rowCallbackHandler)
@Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler)
throws DataAccessException;
/**
@@ -726,14 +724,13 @@ public interface AsyncCqlOperations {
*
* @param preparedStatementCreator object that can create a {@link PreparedStatement} given a
* {@link com.datastax.driver.core.Session}, must not be {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param rowMapper object that will map one object per row, must not be {@literal null}.
* @return the result {@link List}, containing mapped objects.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> ListenableFuture<List<T>> query(AsyncPreparedStatementCreator preparedStatementCreator,
PreparedStatementBinder preparedStatementBinder, RowMapper<T> rowMapper) throws DataAccessException;
@Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper) throws DataAccessException;
}

View File

@@ -24,6 +24,7 @@ import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.cassandra.SessionFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.SettableListenableFuture;
@@ -412,13 +413,13 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder)
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.@Nullablender)
*/
@Override
public ListenableFuture<Boolean> execute(String cql, PreparedStatementBinder preparedStatementBinder)
public ListenableFuture<Boolean> execute(String cql, @Nullable PreparedStatementBinder psb)
throws DataAccessException {
return query(newAsyncPreparedStatementCreator(cql), preparedStatementBinder, ResultSet::wasApplied);
return query(newAsyncPreparedStatementCreator(cql), psb, ResultSet::wasApplied);
}
/*
@@ -441,6 +442,8 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
Assert.notNull(preparedStatementCreator, "PreparedStatementCreator must not be null");
Assert.notNull(action, "PreparedStatementCallback object must not be null");
PersistenceExceptionTranslator exceptionTranslator = ex -> translateExceptionIfPossible("PreparedStatementCallback",
toCql(preparedStatementCreator), ex);
try {
if (logger.isDebugEnabled()) {
logger.debug("Preparing statement [{}] using {}", toCql(preparedStatementCreator), preparedStatementCreator);
@@ -452,12 +455,12 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
try {
return action.doInPreparedStatement(currentSession, applyStatementSettings(preparedStatement));
} catch (DriverException e) {
throw translateException("PreparedStatementCallback", preparedStatement.toString(), e);
throw translateException(exceptionTranslator, e);
}
}), getExceptionTranslator());
} catch (DriverException e) {
throw translateException("PreparedStatementCallback", toCql(preparedStatementCreator), e);
throw translateException(exceptionTranslator, e);
}
}
@@ -503,30 +506,30 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
*/
@Override
public <T> ListenableFuture<T> query(AsyncPreparedStatementCreator preparedStatementCreator,
PreparedStatementBinder preparedStatementBinder, ResultSetExtractor<T> resultSetExtractor)
@Nullable PreparedStatementBinder psb, ResultSetExtractor<T> resultSetExtractor)
throws DataAccessException {
Assert.notNull(preparedStatementCreator, "AsyncPreparedStatementCreator must not be null");
Assert.notNull(resultSetExtractor, "ResultSetExtractor object must not be null");
PersistenceExceptionTranslator exceptionTranslator = ex -> translateExceptionIfPossible("Query",
toCql(preparedStatementCreator), ex);
try {
if (logger.isDebugEnabled()) {
logger.debug("Preparing statement [{}] using {}", toCql(preparedStatementCreator), preparedStatementCreator);
}
Session session = getCurrentSession();
PersistenceExceptionTranslator exceptionTranslator = ex -> translateExceptionIfPossible("Query",
toCql(preparedStatementCreator), ex);
ListenableFuture<BoundStatement> statementFuture = new MappingListenableFutureAdapter<>(
preparedStatementCreator.createPreparedStatement(session), preparedStatement -> {
if (logger.isDebugEnabled()) {
logger.debug("Executing prepared statement [{}]", preparedStatement);
}
return applyStatementSettings(preparedStatementBinder != null
? preparedStatementBinder.bindValues(preparedStatement) : preparedStatement.bind());
return applyStatementSettings(psb != null ? psb.bindValues(preparedStatement) : preparedStatement.bind());
});
SettableListenableFuture<T> settableListenableFuture = new SettableListenableFuture<>();
@@ -534,27 +537,25 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
statementFuture.addCallback(
boundStatement -> Futures.addCallback(session.executeAsync(boundStatement), new FutureCallback<ResultSet>() {
@Override
public void onSuccess(ResultSet result) {
public void onSuccess(@Nullable ResultSet result) {
try {
settableListenableFuture.set(resultSetExtractor.extractData(result));
settableListenableFuture.set(result != null ? resultSetExtractor.extractData(result) : null);
} catch (DriverException e) {
settableListenableFuture.setException(exceptionTranslator.translateExceptionIfPossible(e));
settableListenableFuture.setException(translateException(exceptionTranslator, e));
}
}
@Override
public void onFailure(Throwable ex) {
if (ex instanceof DriverException) {
settableListenableFuture
.setException(exceptionTranslator.translateExceptionIfPossible((DriverException) ex));
settableListenableFuture.setException(translateException(exceptionTranslator, (DriverException) ex));
} else {
settableListenableFuture.setException(ex);
}
}
}), ex -> {
if (ex instanceof DriverException) {
settableListenableFuture
.setException(exceptionTranslator.translateExceptionIfPossible((DriverException) ex));
settableListenableFuture.setException(translateException(exceptionTranslator, (DriverException) ex));
} else {
settableListenableFuture.setException(ex);
}
@@ -563,7 +564,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
return settableListenableFuture;
} catch (DriverException e) {
throw translateException("Query", toCql(preparedStatementCreator), e);
throw translateException(exceptionTranslator, e);
}
}
@@ -573,10 +574,10 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
*/
@Override
public ListenableFuture<Void> query(AsyncPreparedStatementCreator preparedStatementCreator,
PreparedStatementBinder preparedStatementBinder, RowCallbackHandler rowCallbackHandler)
@Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler)
throws DataAccessException {
ListenableFuture<?> results = query(preparedStatementCreator, preparedStatementBinder,
ListenableFuture<?> results = query(preparedStatementCreator, psb,
newResultSetExtractor(rowCallbackHandler));
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null),
@@ -589,9 +590,8 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
*/
@Override
public <T> ListenableFuture<List<T>> query(AsyncPreparedStatementCreator preparedStatementCreator,
PreparedStatementBinder preparedStatementBinder, RowMapper<T> rowMapper) throws DataAccessException {
return query(preparedStatementCreator, preparedStatementBinder, newResultSetExtractor(rowMapper));
@Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper) throws DataAccessException {
return query(preparedStatementCreator, psb, newResultSetExtractor(rowMapper));
}
/*
@@ -601,7 +601,6 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
@Override
public <T> ListenableFuture<T> query(String cql, ResultSetExtractor<T> resultSetExtractor, Object... args)
throws DataAccessException {
return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), resultSetExtractor);
}
@@ -627,7 +626,6 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
@Override
public <T> ListenableFuture<List<T>> query(String cql, RowMapper<T> rowMapper, Object... args)
throws DataAccessException {
return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args),
newResultSetExtractor(rowMapper));
}
@@ -637,10 +635,10 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
*/
@Override
public <T> ListenableFuture<T> query(String cql, PreparedStatementBinder preparedStatementBinder,
public <T> ListenableFuture<T> query(String cql, @Nullable PreparedStatementBinder psb,
ResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
return query(newAsyncPreparedStatementCreator(cql), preparedStatementBinder, resultSetExtractor);
return query(newAsyncPreparedStatementCreator(cql), psb, resultSetExtractor);
}
/*
@@ -648,10 +646,10 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowCallbackHandler)
*/
@Override
public ListenableFuture<Void> query(String cql, PreparedStatementBinder preparedStatementBinder,
public ListenableFuture<Void> query(String cql, @Nullable PreparedStatementBinder psb,
RowCallbackHandler rowCallbackHandler) throws DataAccessException {
ListenableFuture<?> results = query(newAsyncPreparedStatementCreator(cql), preparedStatementBinder,
ListenableFuture<?> results = query(newAsyncPreparedStatementCreator(cql), psb,
newResultSetExtractor(rowCallbackHandler));
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null),
@@ -663,10 +661,10 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowMapper)
*/
@Override
public <T> ListenableFuture<List<T>> query(String cql, PreparedStatementBinder preparedStatementBinder,
public <T> ListenableFuture<List<T>> query(String cql, @Nullable PreparedStatementBinder psb,
RowMapper<T> rowMapper) throws DataAccessException {
return query(newAsyncPreparedStatementCreator(cql), preparedStatementBinder, newResultSetExtractor(rowMapper));
return query(newAsyncPreparedStatementCreator(cql), psb, newResultSetExtractor(rowMapper));
}
/*
@@ -757,13 +755,12 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
* Translate the given {@link DriverException} into a generic {@link DataAccessException}.
*
* @param task readable text describing the task being attempted
* @param cql CQL query or update that caused the problem (may be {@code null})
* @param cql CQL query or update that caused the problem (may be {@literal null})
* @param ex the offending {@code RuntimeException}.
* @return the exception translation {@link Function}
* @see CqlProvider
*/
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
protected DataAccessException translateException(String task, String cql, DriverException ex) {
protected DataAccessException translateException(String task, @Nullable String cql, DriverException ex) {
return translate(task, cql, ex);
}
@@ -771,18 +768,30 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
* Translate the given {@link DriverException} into a generic {@link DataAccessException}.
*
* @param task readable text describing the task being attempted
* @param cql CQL query or update that caused the problem (may be {@code null})
* @param cql CQL query or update that caused the problem (may be {@literal null})
* @param ex the offending {@code RuntimeException}.
* @return the translated {@link DataAccessException} or {@literal null} if translation not possible.
* @see CqlProvider
*/
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
protected DataAccessException translateExceptionIfPossible(String task, String cql, RuntimeException ex) {
@Nullable
protected DataAccessException translateExceptionIfPossible(String task, @Nullable String cql, RuntimeException ex) {
return (ex instanceof DriverException ? translate(task, cql, (DriverException) ex) : null);
}
private Session getCurrentSession() {
return getSessionFactory().getSession();
SessionFactory sessionFactory = getSessionFactory();
Assert.state(sessionFactory != null, "SessionFactory is null");
return sessionFactory.getSession();
}
private static RuntimeException translateException(PersistenceExceptionTranslator exceptionTranslator,
DriverException e) {
DataAccessException translated = exceptionTranslator.translateExceptionIfPossible(e);
return translated == null ? e : translated;
}
private static class SimpleAsyncPreparedStatementCreator implements AsyncPreparedStatementCreator, CqlProvider {

View File

@@ -36,6 +36,7 @@ import com.datastax.driver.core.exceptions.DriverException;
*
* @author Mark Paluch
* @since 2.0
* @see AsyncCqlTemplate#execute(AsyncPreparedStatementCreator, PreparedStatementCallback)
*/
@FunctionalInterface
public interface AsyncPreparedStatementCreator {

View File

@@ -48,7 +48,7 @@ public interface AsyncSessionCallback<T> {
* template.
*
* @param session active Cassandra Session, must not be {@literal null}.
* @return a result object, or {@code null} if none.
* @return a result object, or {@code ListenableFuture<Void>} if none.
* @throws DriverException if thrown by a Session method, to be auto-converted to a {@link DataAccessException}.
* @throws DataAccessException in case of custom exceptions.
* @see AsyncCqlTemplate#queryForObject(String, Class)

View File

@@ -25,6 +25,7 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.data.cassandra.SessionFactory;
import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.ConsistencyLevel;
@@ -59,7 +60,7 @@ public class CassandraAccessor implements InitializingBean {
/** Logger available to subclasses */
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected CqlExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
private CqlExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
/**
* If this variable is set to a non-negative value, it will be used for setting the {@code fetchSize} property on
@@ -71,15 +72,15 @@ public class CassandraAccessor implements InitializingBean {
* If this variable is set to a value, it will be used for setting the {@code consistencyLevel} property on statements
* used for query processing.
*/
private com.datastax.driver.core.ConsistencyLevel consistencyLevel;
private @Nullable com.datastax.driver.core.ConsistencyLevel consistencyLevel;
/**
* If this variable is set to a value, it will be used for setting the {@code retryPolicy} property on statements used
* for query processing.
*/
private com.datastax.driver.core.policies.RetryPolicy retryPolicy;
private @Nullable com.datastax.driver.core.policies.RetryPolicy retryPolicy;
private SessionFactory sessionFactory;
private @Nullable SessionFactory sessionFactory;
/**
* Ensures the Cassandra {@link Session} and exception translator has been propertly set.
@@ -97,13 +98,14 @@ public class CassandraAccessor implements InitializingBean {
* @see Statement#setConsistencyLevel(ConsistencyLevel)
* @see RetryPolicy
*/
public void setConsistencyLevel(ConsistencyLevel consistencyLevel) {
public void setConsistencyLevel(@Nullable ConsistencyLevel consistencyLevel) {
this.consistencyLevel = consistencyLevel;
}
/**
* @return the {@link ConsistencyLevel} specified for this template.
*/
@Nullable
public ConsistencyLevel getConsistencyLevel() {
return this.consistencyLevel;
}
@@ -118,6 +120,7 @@ public class CassandraAccessor implements InitializingBean {
public void setExceptionTranslator(CqlExceptionTranslator exceptionTranslator) {
Assert.notNull(exceptionTranslator, "CQLExceptionTranslator must not be null");
this.exceptionTranslator = exceptionTranslator;
}
@@ -129,9 +132,6 @@ public class CassandraAccessor implements InitializingBean {
* @see CqlExceptionTranslator
*/
public CqlExceptionTranslator getExceptionTranslator() {
Assert.state(this.exceptionTranslator != null, "CQLExceptionTranslator was not properly initialized");
return this.exceptionTranslator;
}
@@ -160,13 +160,14 @@ public class CassandraAccessor implements InitializingBean {
* @see Statement#setRetryPolicy(RetryPolicy)
* @see RetryPolicy
*/
public void setRetryPolicy(RetryPolicy retryPolicy) {
public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
}
/**
* @return the {@link RetryPolicy} specified for this template.
*/
@Nullable
public RetryPolicy getRetryPolicy() {
return this.retryPolicy;
}
@@ -224,6 +225,7 @@ public class CassandraAccessor implements InitializingBean {
* @since 2.0
* @see SessionFactory
*/
@Nullable
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
@@ -300,6 +302,7 @@ public class CassandraAccessor implements InitializingBean {
* exception hierarchy</a>
* @see DataAccessException
*/
@Nullable
protected DataAccessException translateExceptionIfPossible(DriverException ex) {
Assert.notNull(ex, "DriverException must not be null");
@@ -316,7 +319,7 @@ public class CassandraAccessor implements InitializingBean {
* subsequent cast) is considered reliable when expecting Cassandra-based access to have happened.
*
* @param task readable text describing the task being attempted
* @param cql CQL query or update that caused the problem (may be {@code null})
* @param cql CQL query or update that caused the problem (may be {@literal null})
* @param ex the offending {@link DriverException}
* @return the DataAccessException, wrapping the {@code DriverException}
* @see org.springframework.dao.DataAccessException#getRootCause()
@@ -324,7 +327,7 @@ public class CassandraAccessor implements InitializingBean {
* "http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#dao-exceptions">Consistent
* exception hierarchy</a>
*/
protected DataAccessException translate(String task, String cql, DriverException ex) {
protected DataAccessException translate(String task, @Nullable String cql, DriverException ex) {
Assert.notNull(ex, "DriverException must not be null");
@@ -410,10 +413,12 @@ public class CassandraAccessor implements InitializingBean {
* Determine CQL from potential provider object.
*
* @param cqlProvider object that's potentially a {@link CqlProvider}
* @return the CQL string, or {@code null}
* @return the CQL string, or {@literal null}
* @see CqlProvider
*/
protected static String toCql(Object cqlProvider) {
@Nullable
protected static String toCql(@Nullable Object cqlProvider) {
return Optional.ofNullable(cqlProvider) //
.filter(o -> o instanceof CqlProvider) //
.map(o -> (CqlProvider) o) //
@@ -433,10 +438,10 @@ public class CassandraAccessor implements InitializingBean {
}
/* (non-Javadoc)
*
@see org.springframework.data.cassandra.core.cql.ResultSetExtractor#extractData(com.datastax.driver.core.ResultSet)
* @see org.springframework.data.cassandra.core.cql.ResultSetExtractor#extractData(com.datastax.driver.core.ResultSet)
*/
@Override
@Nullable
public Object extractData(ResultSet resultSet) {
StreamSupport.stream(resultSet.spliterator(), false).forEach(rowCallbackHandler::processRow);

View File

@@ -27,6 +27,7 @@ import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.TransientDataAccessResourceException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.cassandra.*;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -59,6 +60,7 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
*/
@Override
@Nullable
public DataAccessException translateExceptionIfPossible(RuntimeException exception) {
if (exception instanceof DataAccessException) {
@@ -76,7 +78,7 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
* @see org.springframework.data.cassandra.cql.CQLExceptionTranslator#translate(java.lang.String, java.lang.String, com.datastax.driver.core.exceptions.DriverException)
*/
@Override
public DataAccessException translate(String task, String cql, DriverException exception) {
public DataAccessException translate(@Nullable String task, @Nullable String cql, DriverException exception) {
String message = buildMessage(task, cql, exception);
@@ -183,11 +185,11 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
* {@link org.springframework.dao.DataAccessException} class.
*
* @param task readable text describing the task being attempted
* @param cql the CQL statement that caused the problem (may be {@code null})
* @param cql the CQL statement that caused the problem (may be {@literal null})
* @param ex the offending {@code DriverException}
* @return the message {@code String} to use
*/
protected String buildMessage(String task, String cql, DriverException ex) {
protected String buildMessage(@Nullable String task, @Nullable String cql, DriverException ex) {
if (StringUtils.hasText(task) || StringUtils.hasText(cql)) {
return task + "; CQL [" + cql + "]; " + ex.getMessage();

View File

@@ -17,6 +17,7 @@ package org.springframework.data.cassandra.core.cql;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.util.LinkedCaseInsensitiveMap;
import com.datastax.driver.core.ColumnDefinitions;
@@ -94,6 +95,7 @@ public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> {
* @param index is the column index.
* @return the Object returned
*/
@Nullable
protected Object getColumnValue(Row row, int index) {
return row.getObject(index);
}

View File

@@ -17,6 +17,8 @@ package org.springframework.data.cassandra.core.cql;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.cassandra.core.mapping.UnsupportedCassandraOperationException;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.exceptions.DriverException;
@@ -40,12 +42,15 @@ public interface CqlExceptionTranslator extends PersistenceExceptionTranslator {
* subsequent cast) is considered reliable when expecting Cassandra-based access to have happened.
*
* @param task readable text describing the task being attempted.
* @param cql CQL query or update that caused the problem (may be {@code null}).
* @param cql CQL query or update that caused the problem (may be {@literal null}).
* @param ex the offending {@link DriverException}.
* @return the DataAccessException, wrapping the {@link DriverException}.
* @see org.springframework.dao.DataAccessException#getRootCause()
*/
default DataAccessException translate(String task, String cql, DriverException ex) {
return translateExceptionIfPossible(ex);
default DataAccessException translate(@Nullable String task, @Nullable String cql, DriverException ex) {
DataAccessException translated = translateExceptionIfPossible(ex);
return translated == null ? new UnsupportedCassandraOperationException("Cannot translate exception", ex)
: translated;
}
}

View File

@@ -35,7 +35,6 @@ import com.datastax.driver.core.TableMetadata;
* @author Mark Paluch
* @author John Blum
* @see #toCql()
* @see #toCql(StringBuilder)
* @see #toString()
*/
public final class CqlIdentifier implements Comparable<CqlIdentifier>, Serializable {
@@ -50,18 +49,18 @@ public final class CqlIdentifier implements Comparable<CqlIdentifier>, Serializa
public static final Pattern QUOTED = Pattern.compile(QUOTED_REGEX);
private String identifier;
private final String identifier;
private String unquoted;
private final String unquoted;
private boolean quoted;
private final boolean quoted;
/**
* Create a new {@link CqlIdentifier} without force-quoting it. It may end up quoted, depending on its value.
*
* @see #cqlId(CharSequence)
*/
public CqlIdentifier(CharSequence identifier) {
private CqlIdentifier(CharSequence identifier) {
this(identifier, false);
}
@@ -78,8 +77,25 @@ public final class CqlIdentifier implements Comparable<CqlIdentifier>, Serializa
* @see #cqlId(CharSequence, boolean)
* @see #quotedCqlId(CharSequence)
*/
public CqlIdentifier(CharSequence identifier, boolean forceQuote) {
setIdentifier(identifier, forceQuote);
private CqlIdentifier(CharSequence identifier, boolean forceQuote) {
Assert.notNull(identifier, "Identifier must not be null");
String string = identifier.toString();
Assert.hasText(string, "Identifier must not be empty");
if (forceQuote || isQuotedIdentifier(string)) {
this.unquoted = string;
this.identifier = "\"" + string + "\"";
this.quoted = true;
} else if (isUnquotedIdentifier(string)) {
this.identifier = this.unquoted = string.toLowerCase();
this.quoted = false;
} else {
throw new IllegalArgumentException(
String.format("given string [%s] is not a valid quoted or unquoted identifier", identifier));
}
}
/**
@@ -123,29 +139,6 @@ public final class CqlIdentifier implements Comparable<CqlIdentifier>, Serializa
return QUOTED.matcher(chars).matches() || ReservedKeyword.isReserved(chars);
}
/**
* Tests & sets the given identifier.
*/
private void setIdentifier(CharSequence identifier, boolean forceQuoting) {
Assert.notNull(identifier, "Identifier must not be null");
String string = identifier.toString();
Assert.hasText(string, "Identifier must not be empty");
if (forceQuoting || isQuotedIdentifier(string)) {
this.unquoted = string;
this.identifier = "\"" + string + "\"";
quoted = true;
} else if (isUnquotedIdentifier(string)) {
this.identifier = this.unquoted = string.toLowerCase();
} else {
throw new IllegalArgumentException(
String.format("given string [%s] is not a valid quoted or unquoted identifier", identifier));
}
}
/**
* Returns the identifier <em>without</em> encasing quotes, regardless of the value of {@link #isQuoted()}. For
* example, if {@link #isQuoted()} is {@code true}, then this value will be the same as {@link #toCql()} and
@@ -167,10 +160,11 @@ public final class CqlIdentifier implements Comparable<CqlIdentifier>, Serializa
/**
* Appends the rendering of this identifier to the given {@link StringBuilder}, then returns that
* {@link StringBuilder}. If {@code null} is given, a new {@link StringBuilder} is created, appended to, and returned.
* {@link StringBuilder}. If {@literal null} is given, a new {@link StringBuilder} is created, appended to, and
* returned.
*/
public StringBuilder toCql(StringBuilder builder) {
return (builder != null ? builder : new StringBuilder()).append(toCql());
return builder.append(toCql());
}
/**
@@ -211,7 +205,7 @@ public final class CqlIdentifier implements Comparable<CqlIdentifier>, Serializa
if (quoted != that.quoted)
return false;
return identifier != null ? identifier.equals(that.identifier) : that.identifier == null;
return identifier.equals(that.identifier);
}
/* (non-Javadoc)
@@ -220,7 +214,7 @@ public final class CqlIdentifier implements Comparable<CqlIdentifier>, Serializa
@Override
public int hashCode() {
int result = identifier != null ? identifier.hashCode() : 0;
int result = identifier.hashCode();
result = 31 * result + (quoted ? 1 : 0);
return result;
}

View File

@@ -23,6 +23,7 @@ import java.util.Map;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet;
@@ -56,6 +57,7 @@ public interface CqlOperations {
* @return a result object returned by the action, or {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
*/
@Nullable
<T> T execute(SessionCallback<T> action) throws DataAccessException;
// -------------------------------------------------------------------------
@@ -95,7 +97,7 @@ public interface CqlOperations {
* @return boolean value whether the statement was applied.
* @throws DataAccessException if there is any problem issuing the execution.
*/
boolean execute(String cql, PreparedStatementBinder psb) throws DataAccessException;
boolean execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException;
/**
* Execute a CQL data access operation, implemented as callback action working on a CQL {@link PreparedStatement}.
@@ -110,6 +112,7 @@ public interface CqlOperations {
* @return a result object returned by the action, or {@literal null}
* @throws DataAccessException if there is any problem
*/
@Nullable
<T> T execute(String cql, PreparedStatementCallback<T> action) throws DataAccessException;
/**
@@ -124,6 +127,7 @@ public interface CqlOperations {
* @throws DataAccessException if there is any problem executing the query.
* @see #query(String, ResultSetExtractor, Object...)
*/
@Nullable
<T> T query(String cql, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
/**
@@ -131,7 +135,7 @@ public interface CqlOperations {
* {@link RowCallbackHandler}.
* <p>
* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a
* {@link PreparedStatement}, use the overloaded {@code query} method with {@code null} as argument array.
* {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}.
@@ -165,6 +169,7 @@ public interface CqlOperations {
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}
* @throws DataAccessException if there is any problem executing the query.
*/
@Nullable
<T> T query(String cql, ResultSetExtractor<T> resultSetExtractor, Object... args) throws DataAccessException;
/**
@@ -196,14 +201,15 @@ public interface CqlOperations {
* Query using a prepared statement, reading the {@link ResultSet} with a {@link ResultSetExtractor}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param resultSetExtractor object that will extract results, must not be {@literal null}.
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}.
* @throws DataAccessException if there is any problem
*/
<T> T query(String cql, PreparedStatementBinder preparedStatementBinder, ResultSetExtractor<T> resultSetExtractor)
@Nullable
<T> T query(String cql, @Nullable PreparedStatementBinder psb, ResultSetExtractor<T> resultSetExtractor)
throws DataAccessException;
/**
@@ -212,13 +218,13 @@ public interface CqlOperations {
* {@link RowCallbackHandler}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
*/
void query(String cql, PreparedStatementBinder preparedStatementBinder, RowCallbackHandler rowCallbackHandler)
void query(String cql, @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler)
throws DataAccessException;
/**
@@ -226,14 +232,14 @@ public interface CqlOperations {
* knows how to bind values to the query, mapping each row to a Java object via a {@link RowMapper}.
*
* @param cql static CQL to execute, must not be empty or {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param rowMapper object that will map one object per row, must not be {@literal null}.
* @return the result {@link List}, containing mapped objects.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> List<T> query(String cql, PreparedStatementBinder preparedStatementBinder, RowMapper<T> rowMapper)
<T> List<T> query(String cql, @Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper)
throws DataAccessException;
/**
@@ -364,6 +370,7 @@ public interface CqlOperations {
* @throws DataAccessException if there is any problem executing the query.
* @see #queryForObject(String, Class, Object[])
*/
@Nullable
<T> T queryForObject(String cql, Class<T> requiredType) throws DataAccessException;
/**
@@ -383,6 +390,7 @@ public interface CqlOperations {
* @throws DataAccessException if there is any problem executing the query.
* @see #queryForObject(String, Class)
*/
@Nullable
<T> T queryForObject(String cql, Class<T> requiredType, Object... args) throws DataAccessException;
/**
@@ -502,6 +510,7 @@ public interface CqlOperations {
* @throws DataAccessException if there is any problem executing the query.
* @see #query(String, ResultSetExtractor, Object...)
*/
@Nullable
<T> T query(Statement statement, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
/**
@@ -509,7 +518,7 @@ public interface CqlOperations {
* {@link RowCallbackHandler}.
* <p>
* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a
* {@link PreparedStatement}, use the overloaded {@code query} method with {@code null} as argument array.
* {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array.
*
* @param statement static CQL {@link Statement}, must not be {@literal null}.
* @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}.
@@ -605,6 +614,7 @@ public interface CqlOperations {
* @throws DataAccessException if there is any problem executing the query.
* @see #queryForObject(String, Class, Object[])
*/
@Nullable
<T> T queryForObject(Statement statement, Class<T> requiredType) throws DataAccessException;
/**
@@ -621,6 +631,7 @@ public interface CqlOperations {
* @throws DataAccessException if there is any problem executing the query.
* @see #queryForObject(String, RowMapper, Object[])
*/
@Nullable
<T> T queryForObject(Statement statement, RowMapper<T> rowMapper) throws DataAccessException;
/**
@@ -684,6 +695,7 @@ public interface CqlOperations {
* @return a result object returned by the action, or {@literal null}.
* @throws DataAccessException if there is any problem
*/
@Nullable
<T> T execute(PreparedStatementCreator preparedStatementCreator, PreparedStatementCallback<T> action)
throws DataAccessException;
@@ -696,6 +708,7 @@ public interface CqlOperations {
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}
* @throws DataAccessException if there is any problem
*/
@Nullable
<T> T query(PreparedStatementCreator preparedStatementCreator, ResultSetExtractor<T> resultSetExtractor)
throws DataAccessException;
@@ -729,14 +742,15 @@ public interface CqlOperations {
*
* @param preparedStatementCreator object that can create a {@link PreparedStatement} given a
* {@link com.datastax.driver.core.Session}, must not be {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param resultSetExtractor object that will extract results, must not be {@literal null}.
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}.
* @throws DataAccessException if there is any problem
*/
<T> T query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder,
@Nullable
<T> T query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb,
ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
/**
@@ -745,13 +759,13 @@ public interface CqlOperations {
*
* @param preparedStatementCreator object that can create a {@link PreparedStatement} given a
* {@link com.datastax.driver.core.Session}, must not be {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
*/
void query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder,
void query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb,
RowCallbackHandler rowCallbackHandler) throws DataAccessException;
/**
@@ -760,14 +774,14 @@ public interface CqlOperations {
*
* @param preparedStatementCreator object that can create a {@link PreparedStatement} given a
* {@link com.datastax.driver.core.Session}, must not be {@literal null}.
* @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is
* {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind
* parameters, this object may be used to set fetch size and other performance options.
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
* set fetch size and other performance options.
* @param rowMapper object that will map one object per row, must not be {@literal null}.
* @return the result {@link List}, containing mapped objects.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> List<T> query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder,
<T> List<T> query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb,
RowMapper<T> rowMapper) throws DataAccessException;
// -------------------------------------------------------------------------
@@ -788,8 +802,7 @@ public interface CqlOperations {
*
* @param hostMapper The implementation to use for host mapping.
* @return Collection generated by the provided HostMapper.
* @throws DataAccessException
* @throws DataAccessException if there is any problem executing the query.
*/
<T> Collection<T> describeRing(HostMapper<T> hostMapper) throws DataAccessException;
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.cassandra.core.cql;
import org.springframework.lang.Nullable;
/**
* Interface to be implemented by objects that can provide CQL strings.
* <p>
@@ -35,5 +37,6 @@ public interface CqlProvider {
*
* @return the CQL string, or {@literal null}.
*/
@Nullable
String getCql();
}

View File

@@ -15,62 +15,68 @@
*/
package org.springframework.data.cassandra.core.cql;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.DataType;
public class CqlStringUtils {
protected static final String DOUBLE_QUOTE = "\"";
protected static final String DOUBLE_DOUBLE_QUOTE = "\"\"";
protected static final String DOUBLE_SINGLE_QUOTE = "\'\'";
protected static final String SINGLE_QUOTE = "\'";
protected static final String EMPTY_STRING = "";
protected static final String TYPE_PARAMETER_PREFIX = "<";
protected static final String TYPE_PARAMETER_SUFFIX = ">";
public static StringBuilder noNull(StringBuilder builder) {
return (builder == null ? new StringBuilder() : builder);
}
private static final String DOUBLE_QUOTE = "\"";
private static final String DOUBLE_DOUBLE_QUOTE = "\"\"";
private static final String DOUBLE_SINGLE_QUOTE = "\'\'";
private static final String SINGLE_QUOTE = "\'";
private static final String EMPTY_STRING = "";
private static final String TYPE_PARAMETER_PREFIX = "<";
private static final String TYPE_PARAMETER_SUFFIX = ">";
/**
* Renders the given string as a legal Cassandra string column or table option value, by escaping single quotes and
* encasing the result in single quotes. Given {@code null}, returns <code>null</code>.
* encasing the result in single quotes. Given {@literal null}, returns <code>null</code>.
*/
public static String valuize(String candidate) {
@Nullable
public static String valuize(@Nullable String candidate) {
return (candidate != null ? singleQuote(escapeSingle(candidate)) : null);
}
/**
* Doubles single quote characters (' -&gt; ''). Given {@code null}, returns <code>null</code>.
* Doubles single quote characters (' -&gt; ''). Given {@literal null}, returns <code>null</code>.
*/
public static String escapeSingle(Object thing) {
@Nullable
public static String escapeSingle(@Nullable Object thing) {
return (thing == null ? null : thing.toString().replace(SINGLE_QUOTE, DOUBLE_SINGLE_QUOTE));
}
/**
* Doubles double quote characters (" -&gt; ""). Given {@code null}, returns <code>null</code>.
* Doubles double quote characters (" -&gt; ""). Given {@literal null}, returns <code>null</code>.
*/
public static String escapeDouble(Object thing) {
@Nullable
public static String escapeDouble(@Nullable Object thing) {
return (thing == null ? null : thing.toString().replace(DOUBLE_QUOTE, DOUBLE_DOUBLE_QUOTE));
}
/**
* Surrounds given object's {@link Object#toString()} with single quotes. Given {@code null}, returns {@code null}.
* Surrounds given object's {@link Object#toString()} with single quotes. Given {@literal null}, returns
* {@literal null}.
*/
public static String singleQuote(Object thing) {
@Nullable
public static String singleQuote(@Nullable Object thing) {
return (thing == null ? null : SINGLE_QUOTE.concat(thing.toString()).concat(SINGLE_QUOTE));
}
/**
* Surrounds given object's {@link Object#toString()} with double quotes. Given {@code null}, returns {@code null}.
* Surrounds given object's {@link Object#toString()} with double quotes. Given {@literal null}, returns
* {@literal null}.
*/
public static String doubleQuote(Object thing) {
@Nullable
public static String doubleQuote(@Nullable Object thing) {
return (thing == null ? null : DOUBLE_QUOTE.concat(thing.toString()).concat(DOUBLE_QUOTE));
}
/**
* Removed single quotes from quoted String option values
*/
public static String removeSingleQuotes(Object thing) {
@Nullable
public static String removeSingleQuotes(@Nullable Object thing) {
return (thing == null ? null : thing.toString().replaceAll(SINGLE_QUOTE, EMPTY_STRING));
}
@@ -105,11 +111,13 @@ public class CqlStringUtils {
return builder.append(TYPE_PARAMETER_SUFFIX).toString();
}
public static String unquote(String value) {
@Nullable
public static String unquote(@Nullable String value) {
return unquote(value, "\"");
}
public static String unquote(String value, String quoteChar) {
@Nullable
public static String unquote(@Nullable String value, String quoteChar) {
if (value == null) {
return null;

View File

@@ -24,6 +24,7 @@ import java.util.function.Function;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.data.cassandra.SessionFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.BoundStatement;
@@ -154,6 +155,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* @see org.springframework.data.cassandra.core.cqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
*/
@Override
@Nullable
public <T> T query(String cql, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
Assert.hasText(cql, "CQL must not be empty");
@@ -189,6 +191,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public <T> List<T> query(String cql, RowMapper<T> rowMapper) throws DataAccessException {
// noinspection ConstantConditions
return query(cql, newResultSetExtractor(rowMapper));
}
@@ -198,6 +201,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public List<Map<String, Object>> queryForList(String cql) throws DataAccessException {
// noinspection ConstantConditions
return query(cql, newResultSetExtractor(newColumnMapRowMapper()));
}
@@ -207,6 +211,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public <T> List<T> queryForList(String cql, Class<T> elementType) throws DataAccessException {
// noinspection ConstantConditions
return query(cql, newResultSetExtractor(newSingleColumnRowMapper(elementType)));
}
@@ -243,6 +248,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public ResultSet queryForResultSet(String cql) throws DataAccessException {
// noinspection ConstantConditions
return query(cql, rs -> rs);
}
@@ -307,6 +313,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public <T> List<T> query(Statement statement, RowMapper<T> rowMapper) throws DataAccessException {
// noinspection ConstantConditions
return query(statement, newResultSetExtractor(rowMapper));
}
@@ -316,6 +323,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public List<Map<String, Object>> queryForList(Statement statement) throws DataAccessException {
// noinspection ConstantConditions
return query(statement, newResultSetExtractor(newColumnMapRowMapper()));
}
@@ -325,6 +333,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public <T> List<T> queryForList(Statement statement, Class<T> elementType) throws DataAccessException {
// noinspection ConstantConditions
return query(statement, newResultSetExtractor(newSingleColumnRowMapper(elementType)));
}
@@ -334,6 +343,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public Map<String, Object> queryForMap(Statement statement) throws DataAccessException {
// noinspection ConstantConditions
return queryForObject(statement, newColumnMapRowMapper());
}
@@ -361,6 +371,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public ResultSet queryForResultSet(Statement statement) throws DataAccessException {
// noinspection ConstantConditions
return query(statement, rs -> rs);
}
@@ -391,14 +402,16 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* @see org.springframework.data.cassandra.core.cqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder)
*/
@Override
public boolean execute(String cql, PreparedStatementBinder preparedStatementBinder) throws DataAccessException {
return query(new SimplePreparedStatementCreator(cql), preparedStatementBinder, ResultSet::wasApplied);
public boolean execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException {
// noinspection ConstantConditions
return query(new SimplePreparedStatementCreator(cql), psb, ResultSet::wasApplied);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementCallback)
*/
@Nullable
@Override
public <T> T execute(String cql, PreparedStatementCallback<T> action) throws DataAccessException {
return execute(newPreparedStatementCreator(cql), action);
@@ -410,6 +423,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public boolean execute(PreparedStatementCreator preparedStatementCreator) throws DataAccessException {
// noinspection ConstantConditions
return query(preparedStatementCreator, ResultSet::wasApplied);
}
@@ -418,6 +432,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* @see org.springframework.data.cassandra.core.cqlOperations#execute(org.springframework.data.cassandra.core.cql.PreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementCallback)
*/
@Override
@Nullable
public <T> T execute(PreparedStatementCreator preparedStatementCreator, PreparedStatementCallback<T> action)
throws DataAccessException {
@@ -468,7 +483,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
@Override
public <T> List<T> query(PreparedStatementCreator preparedStatementCreator, RowMapper<T> rowMapper)
throws DataAccessException {
// noinspection ConstantConditions
return query(preparedStatementCreator, null, newResultSetExtractor(rowMapper));
}
@@ -476,8 +491,9 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cqlOperations#query(org.springframework.data.cassandra.core.cql.PreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
*/
@Nullable
@Override
public <T> T query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder,
public <T> T query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb,
ResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
Assert.notNull(preparedStatementCreator, "PreparedStatementCreator must not be null");
@@ -496,8 +512,8 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
logger.debug("Executing prepared statement [{}]", preparedStatement);
}
BoundStatement boundStatement = applyStatementSettings(preparedStatementBinder != null
? preparedStatementBinder.bindValues(preparedStatement) : preparedStatement.bind());
BoundStatement boundStatement = applyStatementSettings(
psb != null ? psb.bindValues(preparedStatement) : preparedStatement.bind());
ResultSet results = session.execute(boundStatement);
@@ -513,10 +529,10 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* @see org.springframework.data.cassandra.core.cqlOperations#query(org.springframework.data.cassandra.core.cql.PreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowCallbackHandler)
*/
@Override
public void query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder,
public void query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb,
RowCallbackHandler rowCallbackHandler) throws DataAccessException {
query(preparedStatementCreator, preparedStatementBinder, newResultSetExtractor(rowCallbackHandler));
query(preparedStatementCreator, psb, newResultSetExtractor(rowCallbackHandler));
}
/*
@@ -525,9 +541,9 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public <T> List<T> query(PreparedStatementCreator preparedStatementCreator,
PreparedStatementBinder preparedStatementBinder, RowMapper<T> rowMapper) throws DataAccessException {
return query(preparedStatementCreator, preparedStatementBinder, newResultSetExtractor(rowMapper));
@Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper) throws DataAccessException {
// noinspection ConstantConditions
return query(preparedStatementCreator, psb, newResultSetExtractor(rowMapper));
}
/*
@@ -556,6 +572,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public <T> List<T> query(String cql, RowMapper<T> rowMapper, Object... args) throws DataAccessException {
// noinspection ConstantConditions
return query(newPreparedStatementCreator(cql), newPreparedStatementBinder(args), newResultSetExtractor(rowMapper));
}
@@ -564,10 +581,10 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* @see org.springframework.data.cassandra.core.cqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
*/
@Override
public <T> T query(String cql, PreparedStatementBinder preparedStatementBinder,
public <T> T query(String cql, @Nullable PreparedStatementBinder psb,
ResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
return query(newPreparedStatementCreator(cql), preparedStatementBinder, resultSetExtractor);
return query(newPreparedStatementCreator(cql), psb, resultSetExtractor);
}
/*
@@ -575,10 +592,9 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* @see org.springframework.data.cassandra.core.cqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowCallbackHandler)
*/
@Override
public void query(String cql, PreparedStatementBinder preparedStatementBinder, RowCallbackHandler rowCallbackHandler)
public void query(String cql, @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler)
throws DataAccessException {
query(newPreparedStatementCreator(cql), preparedStatementBinder, newResultSetExtractor(rowCallbackHandler));
query(newPreparedStatementCreator(cql), psb, newResultSetExtractor(rowCallbackHandler));
}
/*
@@ -586,10 +602,10 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* @see org.springframework.data.cassandra.core.cqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowMapper)
*/
@Override
public <T> List<T> query(String cql, PreparedStatementBinder preparedStatementBinder, RowMapper<T> rowMapper)
public <T> List<T> query(String cql, @Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper)
throws DataAccessException {
return query(newPreparedStatementCreator(cql), preparedStatementBinder, newResultSetExtractor(rowMapper));
// noinspection ConstantConditions
return query(newPreparedStatementCreator(cql), psb, newResultSetExtractor(rowMapper));
}
/*
@@ -598,6 +614,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public List<Map<String, Object>> queryForList(String cql, Object... args) throws DataAccessException {
// noinspection ConstantConditions
return query(newPreparedStatementCreator(cql), newPreparedStatementBinder(args),
newResultSetExtractor(newColumnMapRowMapper()));
}
@@ -608,6 +625,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public <T> List<T> queryForList(String cql, Class<T> elementType, Object... args) throws DataAccessException {
// noinspection ConstantConditions
return query(newPreparedStatementCreator(cql), newPreparedStatementBinder(args),
newResultSetExtractor(newSingleColumnRowMapper(elementType)));
}
@@ -646,6 +664,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
*/
@Override
public ResultSet queryForResultSet(String cql, Object... args) throws DataAccessException {
// noinspection ConstantConditions
return query(newPreparedStatementCreator(cql), newPreparedStatementBinder(args), rs -> rs);
}
@@ -697,18 +716,22 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* Translate the given {@link DriverException} into a generic {@link DataAccessException}.
*
* @param task readable text describing the task being attempted
* @param cql CQL query or update that caused the problem (may be {@code null})
* @param cql CQL query or update that caused the problem (may be {@literal null})
* @param driverException the offending {@code RuntimeException}.
* @return the exception translation {@link Function}
* @see CqlProvider
*/
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
protected DataAccessException translateException(String task, String cql, DriverException driverException) {
protected DataAccessException translateException(String task, @Nullable String cql, DriverException driverException) {
return translate(task, cql, driverException);
}
private Session getCurrentSession() {
return getSessionFactory().getSession();
SessionFactory sessionFactory = getSessionFactory();
Assert.state(sessionFactory != null, "SessionFactory is null");
return sessionFactory.getSession();
}
private class SimplePreparedStatementCreator implements PreparedStatementCreator, CqlProvider {

View File

@@ -21,6 +21,7 @@ import java.util.concurrent.TimeoutException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.FailureCallback;
import org.springframework.util.concurrent.ListenableFuture;
@@ -38,6 +39,7 @@ import org.springframework.util.concurrent.SuccessCallback;
class ExceptionTranslatingListenableFutureAdapter<T> implements ListenableFuture<T> {
private final ListenableFuture<T> adaptee;
private final ListenableFuture<T> future;
/**
@@ -47,7 +49,7 @@ class ExceptionTranslatingListenableFutureAdapter<T> implements ListenableFuture
* @param adaptee must not be {@literal null}.
* @param persistenceExceptionTranslator must not be {@literal null}.
*/
public ExceptionTranslatingListenableFutureAdapter(ListenableFuture<T> adaptee,
ExceptionTranslatingListenableFutureAdapter(ListenableFuture<T> adaptee,
PersistenceExceptionTranslator persistenceExceptionTranslator) {
Assert.notNull(adaptee, "ListenableFuture must not be null");
@@ -65,7 +67,7 @@ class ExceptionTranslatingListenableFutureAdapter<T> implements ListenableFuture
listenableFuture.addCallback(new ListenableFutureCallback<T>() {
@Override
public void onSuccess(T result) {
public void onSuccess(@Nullable T result) {
settableFuture.set(result);
}

View File

@@ -21,6 +21,7 @@ import java.util.concurrent.TimeoutException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.FailureCallback;
import org.springframework.util.concurrent.ListenableFuture;
@@ -41,6 +42,7 @@ import com.google.common.util.concurrent.Futures;
public class GuavaListenableFutureAdapter<T> implements ListenableFuture<T> {
private final com.google.common.util.concurrent.ListenableFuture<T> adaptee;
private final ListenableFuture<T> future;
/**
@@ -68,7 +70,7 @@ public class GuavaListenableFutureAdapter<T> implements ListenableFuture<T> {
Futures.addCallback(guavaFuture, new FutureCallback<T>() {
@Override
public void onSuccess(T result) {
public void onSuccess(@Nullable T result) {
settableFuture.set(result);
}

View File

@@ -25,9 +25,7 @@ import org.springframework.util.Assert;
* Keyspace identifiers are converted to lower case. To render, use any of the methods {@link #toCql()},
* {@link #toCql(StringBuilder)}, or {@link #toString()}.
*
* @see #KeyspaceIdentifier(String)
* @see #toCql()
* @see #toCql(StringBuilder)
* @see #toString()
* @author Matthew T. Adams
*/
@@ -36,6 +34,25 @@ public final class KeyspaceIdentifier implements Comparable<KeyspaceIdentifier>
public static final String REGEX = "(?i)[a-z][\\w]{0,47}";
public static final Pattern PATTERN = Pattern.compile(REGEX);
private final String identifier;
/**
* Create a new {@link KeyspaceIdentifier}.
*/
private KeyspaceIdentifier(CharSequence identifier) {
Assert.notNull(identifier, "Identifier must not be null");
String string = identifier.toString();
Assert.hasText(string, "Identifier must not be empty");
if (!isIdentifier(string)) {
throw new IllegalArgumentException(
String.format("given string [%s] is not a valid keyspace identifier", identifier));
}
this.identifier = string.toLowerCase();
}
/**
* Factory method for {@link KeyspaceIdentifier}. Convenient if imported statically.
*/
@@ -50,32 +67,6 @@ public final class KeyspaceIdentifier implements Comparable<KeyspaceIdentifier>
return PATTERN.matcher(chars).matches() && !ReservedKeyword.isReserved(chars);
}
private String identifier;
/**
* Create a new {@link KeyspaceIdentifier}.
*/
public KeyspaceIdentifier(CharSequence identifier) {
setIdentifier(identifier);
}
/**
* Tests & sets the given identifier.
*/
private void setIdentifier(CharSequence identifier) {
Assert.notNull(identifier, "Identifier must not be null");
String string = identifier.toString();
Assert.hasText(string, "Identifier must not be empty");
if (!isIdentifier(string)) {
throw new IllegalArgumentException(
String.format("given string [%s] is not a valid keyspace identifier", identifier));
}
this.identifier = string.toLowerCase();
}
/**
* Renders this identifier appropriately.
*/
@@ -85,10 +76,10 @@ public final class KeyspaceIdentifier implements Comparable<KeyspaceIdentifier>
/**
* Appends the rendering of this identifier to the given {@link StringBuilder}, then returns that
* {@link StringBuilder}. If {@code null} is given, a new {@link StringBuilder} is created, appended to, and returned.
* {@link StringBuilder}. If {@literal null} is given, a new {@link StringBuilder} is created, appended to, and
* returned.
*/
public StringBuilder toCql(StringBuilder sb) {
sb = sb == null ? new StringBuilder() : sb;
return sb.append(toCql());
}

View File

@@ -16,6 +16,7 @@
package org.springframework.data.cassandra.core.cql;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.Session;
@@ -36,7 +37,7 @@ import com.datastax.driver.core.exceptions.DriverException;
* @author Mark Paluch
* @see AsyncCqlTemplate#execute(String, PreparedStatementCallback)
* @see AsyncCqlTemplate#execute(AsyncPreparedStatementCreator, PreparedStatementCallback)
* @see CqlTemplate#execute(String, PreparedStatementCallback)
* @see CqlTemplate#execute(String, PreparedStatementCallback)}
* @see CqlTemplate#execute(PreparedStatementCreator, PreparedStatementCallback)
*/
@FunctionalInterface
@@ -58,10 +59,11 @@ public interface PreparedStatementCallback<T> {
* @throws DriverException if thrown by a session method, to be auto-converted to a {@link DataAccessException}.
* @throws DataAccessException in case of custom exceptions.
* @see AsyncCqlTemplate#queryForObject(String, Class, Object...)
* @see AsyncCqlTemplate#queryForList(String, Class, Object...)
* @see AsyncCqlOperations#queryForList(String, Class, Object...)
* @see CqlTemplate#queryForObject(String, Class, Object...)
* @see CqlTemplate#queryForList(String, Object...)
*/
@Nullable
T doInPreparedStatement(Session session, PreparedStatement preparedStatement)
throws DriverException, DataAccessException;
}

View File

@@ -15,9 +15,10 @@
*/
package org.springframework.data.cassandra.core.cql;
import java.util.Optional;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.ConsistencyLevel;
@@ -33,30 +34,53 @@ import com.datastax.driver.core.policies.RetryPolicy;
*/
public class QueryOptions {
private ConsistencyLevel consistencyLevel;
private static final QueryOptions EMPTY = QueryOptions.builder().build();
private RetryPolicy retryPolicy;
private final @Nullable ConsistencyLevel consistencyLevel;
private Boolean tracing;
private final @Nullable RetryPolicy retryPolicy;
private Integer fetchSize;
private final @Nullable Boolean tracing;
private Long readTimeout;
private final @Nullable Integer fetchSize;
/**
* Creates new {@link QueryOptions}.
*/
public QueryOptions() {}
private final Duration readTimeout;
protected QueryOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout) {
this.consistencyLevel = consistencyLevel;
this.retryPolicy = retryPolicy;
this.tracing = tracing;
this.fetchSize = fetchSize;
this.readTimeout = readTimeout;
}
/**
* Creates new {@link QueryOptions} for the given {@link ConsistencyLevel} and {@link RetryPolicy}.
*
* @param consistencyLevel the consistency level, may be {@literal null}.
* @param retryPolicy the retry policy, may be {@literal null}.
* @deprecated since 2.0, use {@link #builder()}.
*/
public QueryOptions(ConsistencyLevel consistencyLevel, RetryPolicy retryPolicy) {
setConsistencyLevel(consistencyLevel);
setRetryPolicy(retryPolicy);
@Deprecated
public QueryOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy) {
this.consistencyLevel = consistencyLevel;
this.retryPolicy = retryPolicy;
this.tracing = false;
this.fetchSize = null;
this.readTimeout = Duration.ofMillis(-1);
}
/**
* Create default {@link QueryOptions}.
*
* @return default {@link QueryOptions}.
* @since 2.0
*/
public static QueryOptions empty() {
return EMPTY;
}
/**
@@ -69,111 +93,45 @@ public class QueryOptions {
return new QueryOptionsBuilder();
}
/**
* Sets the driver {@link ConsistencyLevel}. Setting both ({@link ConsistencyLevel} and {@link ConsistencyLevel driver
* ConsistencyLevel}) consistency levels is not supported.
*
* @param consistencyLevel the driver {@link ConsistencyLevel} to set.
* @since 1.5
*/
public void setConsistencyLevel(ConsistencyLevel consistencyLevel) {
this.consistencyLevel = consistencyLevel;
}
/**
* @return the the driver {@link ConsistencyLevel}
* @since 1.5
*/
@Nullable
protected ConsistencyLevel getConsistencyLevel() {
return this.consistencyLevel;
}
/**
* Sets the {@link RetryPolicy}. Setting both ({@link RetryPolicy} and {@link RetryPolicy driver RetryPolicy}) retry
* policies is not supported.
*
* @param retryPolicy the driver {@link RetryPolicy} to set.
* @since 1.5
* @throws IllegalStateException if the {@link RetryPolicy} is set
*/
public void setRetryPolicy(RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
}
/**
* @return the driver {@link RetryPolicy}
* @since 1.5
*/
@Nullable
protected RetryPolicy getRetryPolicy() {
return this.retryPolicy;
}
/**
* Sets the query fetch size for {@link com.datastax.driver.core.ResultSet} chunks.
* <p>
* The fetch size controls how much resulting rows will be retrieved simultaneously (the goal being to avoid loading
* too much results in memory for queries yielding large results). Please note that while value as low as 1 can be
* used, it is *highly* discouraged to use such a low value in practice as it will yield very poor performance.
*
* @param fetchSize the number of rows to fetch per chunking request. To disable chunking of the result set, use
* {@code fetchSize == Integer.MAX_VALUE}. Negative values are not allowed.
* @since 1.5
* @see com.datastax.driver.core.QueryOptions#getFetchSize()
* @see com.datastax.driver.core.Cluster.Builder#withQueryOptions(com.datastax.driver.core.QueryOptions)
*/
public void setFetchSize(int fetchSize) {
Assert.isTrue(fetchSize >= 0, "FetchSize must be greater than equal to zero");
this.fetchSize = fetchSize;
}
/**
* @return the number of rows to fetch per chunking request. May be {@literal null} if not set.
* @since 1.5
*/
@Nullable
protected Integer getFetchSize() {
return fetchSize;
}
/**
* Sets the read timeout in milliseconds. Overrides the default per-host read timeout (
* {@link SocketOptions#getReadTimeoutMillis()}).
*
* @param readTimeout the read timeout in milliseconds. Negative values are not allowed. If it is {@code 0}, the read
* timeout will be disabled for this statement.
* @since 1.5
* @see SocketOptions#getReadTimeoutMillis()
* @see com.datastax.driver.core.Cluster.Builder#withSocketOptions(SocketOptions)
*/
public void setReadTimeout(long readTimeout) {
Assert.isTrue(readTimeout >= 0, "ReadTimeout must be greater than equal to zero");
this.readTimeout = readTimeout;
}
/**
* @return the read timeout in milliseconds. May be {@literal null} if not set.
* @since 1.5
*/
protected Long getReadTimeout() {
protected Duration getReadTimeout() {
return this.readTimeout;
}
/**
* Enables statement tracing.
*
* @param tracing {@literal true} to enable statement tracing to the executed statements.
* @since 1.5
*/
public void setTracing(boolean tracing) {
this.tracing = tracing;
}
/**
* @return whether to enable tracing. May be {@literal null} if not set.
*/
@Nullable
protected Boolean getTracing() {
return this.tracing;
}
@@ -186,15 +144,15 @@ public class QueryOptions {
*/
public static class QueryOptionsBuilder {
private ConsistencyLevel consistencyLevel;
protected @Nullable ConsistencyLevel consistencyLevel;
private RetryPolicy retryPolicy;
protected @Nullable RetryPolicy retryPolicy;
private Boolean tracing;
protected @Nullable Boolean tracing;
private Integer fetchSize;
protected @Nullable Integer fetchSize;
private Long readTimeout;
protected Duration readTimeout = Duration.ofMillis(-1);
QueryOptionsBuilder() {}
@@ -261,12 +219,7 @@ public class QueryOptions {
* @see com.datastax.driver.core.Cluster.Builder#withSocketOptions(SocketOptions)
*/
public QueryOptionsBuilder readTimeout(long readTimeout) {
Assert.isTrue(readTimeout >= 0, "ReadTimeout must be greater than equal to zero");
this.readTimeout = readTimeout;
return this;
return readTimeout(Duration.ofMillis(readTimeout));
}
/**
@@ -278,13 +231,33 @@ public class QueryOptions {
* @return {@code this} {@link QueryOptionsBuilder}
* @see SocketOptions#getReadTimeoutMillis()
* @see com.datastax.driver.core.Cluster.Builder#withSocketOptions(SocketOptions)
* @deprecated since 2.0, use {@link #readTimeout(Duration)}.
*/
@Deprecated
public QueryOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) {
Assert.isTrue(readTimeout >= 0, "ReadTimeout must be greater than equal to zero");
Assert.notNull(timeUnit, "TimeUnit must not be null");
this.readTimeout = timeUnit.toMillis(readTimeout);
return readTimeout(Duration.ofMillis(timeUnit.toMillis(readTimeout)));
}
/**
* Sets the read timeout. Overrides the default per-host read timeout.
*
* @param readTimeout the read timeout. Negative values are not allowed. If it is {@code 0}, the read timeout will
* be disabled for this statement.
* @return {@code this} {@link QueryOptionsBuilder}
* @see SocketOptions#getReadTimeoutMillis()
* @see com.datastax.driver.core.Cluster.Builder#withSocketOptions(SocketOptions)
* @since 2.0
*/
public QueryOptionsBuilder readTimeout(Duration readTimeout) {
Assert.isTrue(!readTimeout.isZero() && !readTimeout.isNegative(),
"ReadTimeout must be greater than equal to zero");
this.readTimeout = readTimeout;
return this;
}
@@ -317,21 +290,7 @@ public class QueryOptions {
* @return a new {@link QueryOptions} with the configured values
*/
public QueryOptions build() {
return applyOptions(new QueryOptions());
}
protected <T> T applyOptions(T options) {
QueryOptions queryOptions = (QueryOptions) options;
queryOptions.setConsistencyLevel(consistencyLevel);
queryOptions.setRetryPolicy(retryPolicy);
Optional.ofNullable(this.fetchSize).ifPresent(queryOptions::setFetchSize);
Optional.ofNullable(this.readTimeout).ifPresent(queryOptions::setReadTimeout);
Optional.ofNullable(this.tracing).ifPresent(queryOptions::setTracing);
return options;
return new QueryOptions(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout);
}
}
}

View File

@@ -42,13 +42,11 @@ public abstract class QueryOptionsUtil {
Assert.notNull(preparedStatement, "PreparedStatement must not be null");
if (queryOptions != null) {
if (queryOptions.getConsistencyLevel() != null) {
preparedStatement.setConsistencyLevel(queryOptions.getConsistencyLevel());
}
if (queryOptions.getRetryPolicy() != null) {
preparedStatement.setRetryPolicy(queryOptions.getRetryPolicy());
}
if (queryOptions.getConsistencyLevel() != null) {
preparedStatement.setConsistencyLevel(queryOptions.getConsistencyLevel());
}
if (queryOptions.getRetryPolicy() != null) {
preparedStatement.setRetryPolicy(queryOptions.getRetryPolicy());
}
return preparedStatement;
@@ -65,29 +63,27 @@ public abstract class QueryOptionsUtil {
Assert.notNull(statement, "Statement must not be null");
if (queryOptions != null) {
if (queryOptions.getConsistencyLevel() != null) {
statement.setConsistencyLevel(queryOptions.getConsistencyLevel());
}
if (queryOptions.getConsistencyLevel() != null) {
statement.setConsistencyLevel(queryOptions.getConsistencyLevel());
}
if (queryOptions.getRetryPolicy() != null) {
statement.setRetryPolicy(queryOptions.getRetryPolicy());
}
if (queryOptions.getRetryPolicy() != null) {
statement.setRetryPolicy(queryOptions.getRetryPolicy());
}
if (queryOptions.getFetchSize() != null) {
statement.setFetchSize(queryOptions.getFetchSize());
}
if (queryOptions.getFetchSize() != null) {
statement.setFetchSize(queryOptions.getFetchSize());
}
if (queryOptions.getReadTimeout() != null) {
statement.setReadTimeoutMillis(queryOptions.getReadTimeout().intValue());
}
if (!queryOptions.getReadTimeout().isNegative()) {
statement.setReadTimeoutMillis(Math.toIntExact(queryOptions.getReadTimeout().toMillis()));
}
if (queryOptions.getTracing() != null) {
if (queryOptions.getTracing()) {
statement.enableTracing();
} else {
statement.disableTracing();
}
if (queryOptions.getTracing() != null) {
if (queryOptions.getTracing()) {
statement.enableTracing();
} else {
statement.disableTracing();
}
}
@@ -105,12 +101,10 @@ public abstract class QueryOptionsUtil {
Assert.notNull(insert, "Insert must not be null");
if (writeOptions != null) {
addQueryOptions(insert, writeOptions);
addQueryOptions(insert, writeOptions);
if (writeOptions.getTtl() != null) {
insert.using(QueryBuilder.ttl(writeOptions.getTtl()));
}
if (!writeOptions.getTtl().isNegative()) {
insert.using(QueryBuilder.ttl(Math.toIntExact(writeOptions.getTtl().getSeconds())));
}
return insert;
@@ -127,12 +121,10 @@ public abstract class QueryOptionsUtil {
Assert.notNull(update, "Update must not be null");
if (writeOptions != null) {
addQueryOptions(update, writeOptions);
addQueryOptions(update, writeOptions);
if (writeOptions.getTtl() != null) {
update.using(QueryBuilder.ttl(writeOptions.getTtl()));
}
if (!writeOptions.getTtl().isNegative()) {
update.using(QueryBuilder.ttl(Math.toIntExact(writeOptions.getTtl().getSeconds())));
}
return update;

View File

@@ -21,6 +21,7 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.data.cassandra.ReactiveSession;
import org.springframework.data.cassandra.ReactiveSessionFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.exceptions.DriverException;
@@ -44,7 +45,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean {
private CqlExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
private ReactiveSessionFactory sessionFactory;
private @Nullable ReactiveSessionFactory sessionFactory;
/**
* Sets the {@link ReactiveSessionFactory} to use.
@@ -63,6 +64,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean {
*
* @return the configured {@link ReactiveSessionFactory}.
*/
@Nullable
public ReactiveSessionFactory getSessionFactory() {
return sessionFactory;
}
@@ -97,9 +99,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean {
*/
@Override
public void afterPropertiesSet() {
Assert.notNull(sessionFactory != null, "ReactiveSessionFactory must not be null");
Assert.notNull(exceptionTranslator != null, "CassandraExceptionTranslator must not be null");
Assert.notNull(sessionFactory, "ReactiveSessionFactory must not be null");
}
/**
@@ -117,6 +117,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean {
* exception hierarchy</a>
* @see DataAccessException
*/
@Nullable
protected DataAccessException translateExceptionIfPossible(DriverException ex) {
Assert.notNull(ex, "DriverException must not be null");
@@ -133,7 +134,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean {
* subsequent cast) is considered reliable when expecting Cassandra-based access to have happened.
*
* @param task readable text describing the task being attempted
* @param cql CQL query or update that caused the problem (may be {@code null})
* @param cql CQL query or update that caused the problem (may be {@literal null})
* @param ex the offending {@link DriverException}
* @return the DataAccessException, wrapping the {@code DriverException}
* @see org.springframework.dao.DataAccessException#getRootCause()
@@ -141,7 +142,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean {
* "http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#dao-exceptions">Consistent
* exception hierarchy</a>
*/
protected DataAccessException translate(String task, String cql, DriverException ex) {
protected DataAccessException translate(String task, @Nullable String cql, DriverException ex) {
Assert.notNull(ex, "DriverException must not be null");

View File

@@ -24,6 +24,7 @@ import org.reactivestreams.Publisher;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.cassandra.ReactiveResultSet;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.Row;
@@ -47,10 +48,10 @@ public interface ReactiveCqlOperations {
// -------------------------------------------------------------------------
/**
* Execute a CQL data access operation, implemented as callback action working on a {@link ReactiveSession}. This
* allows for implementing arbitrary data access operations, within Spring's managed CQL environment: that is,
* converting CQL {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's
* {@link DataAccessException} hierarchy.
* Execute a CQL data access operation, implemented as callback action working on a
* {@link org.springframework.data.cassandra.ReactiveSession}. This allows for implementing arbitrary data access
* operations, within Spring's managed CQL environment: that is, converting CQL
* {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's {@link DataAccessException} hierarchy.
* <p>
* The callback action can return a result object, for example a domain object or a collection of domain objects.
*
@@ -409,8 +410,8 @@ public interface ReactiveCqlOperations {
* <p>
* The callback action can return a result object, for example a domain object or a collection of domain objects.
*
* @param psc object that can create a {@link PreparedStatement} given a {@link ReactiveSession}, must not be
* {@literal null}.
* @param psc object that can create a {@link PreparedStatement} given a
* {@link org.springframework.data.cassandra.ReactiveSession}, must not be {@literal null}.
* @param action callback object that specifies the action, must not be {@literal null}.
* @return a result object returned by the action, or {@literal null}.
* @throws DataAccessException if there is any problem
@@ -436,8 +437,8 @@ public interface ReactiveCqlOperations {
/**
* Query using a prepared statement, reading the {@link ReactiveResultSet} with a {@link ReactiveResultSetExtractor}.
*
* @param psc object that can create a {@link PreparedStatement} given a {@link ReactiveSession}, must not be
* {@literal null}.
* @param psc object that can create a {@link PreparedStatement} given a
* {@link org.springframework.data.cassandra.ReactiveSession}, must not be {@literal null}.
* @param rse object that will extract results, must not be {@literal null}.
* @return an arbitrary result object, as returned by the {@link ReactiveResultSetExtractor}
* @throws DataAccessException if there is any problem
@@ -455,7 +456,7 @@ public interface ReactiveCqlOperations {
* @return an arbitrary result object, as returned by the {@link ReactiveResultSetExtractor}.
* @throws DataAccessException if there is any problem
*/
<T> Flux<T> query(String cql, PreparedStatementBinder psb, ReactiveResultSetExtractor<T> rse)
<T> Flux<T> query(String cql, @Nullable PreparedStatementBinder psb, ReactiveResultSetExtractor<T> rse)
throws DataAccessException;
/**
@@ -471,7 +472,7 @@ public interface ReactiveCqlOperations {
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}.
* @throws DataAccessException if there is any problem
*/
<T> Flux<T> query(ReactivePreparedStatementCreator psc, PreparedStatementBinder psb,
<T> Flux<T> query(ReactivePreparedStatementCreator psc, @Nullable PreparedStatementBinder psb,
ReactiveResultSetExtractor<T> rse) throws DataAccessException;
/**
@@ -490,8 +491,8 @@ public interface ReactiveCqlOperations {
/**
* Query using a prepared statement, mapping each row to a Java object via a {@link RowMapper}.
*
* @param psc object that can create a {@link PreparedStatement} given a {@link ReactiveSession}, must not be
* {@literal null}.
* @param psc object that can create a {@link PreparedStatement} given a
* {@link org.springframework.data.cassandra.ReactiveSession}, must not be {@literal null}.
* @param rowMapper object that will map one object per row, must not be {@literal null}.
* @return the result {@link Flux}, containing mapped objects.
* @throws DataAccessException if there is any problem executing the query.
@@ -510,7 +511,8 @@ public interface ReactiveCqlOperations {
* @return the result {@link Flux}, containing mapped objects.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> Flux<T> query(String cql, PreparedStatementBinder psb, RowMapper<T> rowMapper) throws DataAccessException;
<T> Flux<T> query(String cql, @Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper)
throws DataAccessException;
/**
* Query using a prepared statement and a {@link PreparedStatementBinder} implementation that knows how to bind values
@@ -525,7 +527,7 @@ public interface ReactiveCqlOperations {
* @return the result {@link Flux}, containing mapped objects.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> Flux<T> query(ReactivePreparedStatementCreator psc, PreparedStatementBinder psb, RowMapper<T> rowMapper)
<T> Flux<T> query(ReactivePreparedStatementCreator psc, @Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper)
throws DataAccessException;
/**
@@ -682,7 +684,7 @@ public interface ReactiveCqlOperations {
* @return boolean value whether the statement was applied.
* @throws DataAccessException if there is any problem issuing the execution.
*/
Mono<Boolean> execute(String cql, PreparedStatementBinder psb) throws DataAccessException;
Mono<Boolean> execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException;
/**
* Issue a single CQL operation (such as an insert, update or delete statement) via a prepared statement, binding the

View File

@@ -29,6 +29,7 @@ import org.springframework.data.cassandra.ReactiveResultSet;
import org.springframework.data.cassandra.ReactiveSession;
import org.springframework.data.cassandra.ReactiveSessionFactory;
import org.springframework.data.cassandra.core.cql.session.DefaultReactiveSessionFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.BoundStatement;
@@ -95,13 +96,13 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* If this variable is set to a value, it will be used for setting the {@code retryPolicy} property on statements used
* for query processing.
*/
private RetryPolicy retryPolicy;
private @Nullable RetryPolicy retryPolicy;
/**
* If this variable is set to a value, it will be used for setting the {@code consistencyLevel} property on statements
* used for query processing.
*/
private com.datastax.driver.core.ConsistencyLevel consistencyLevel;
private @Nullable com.datastax.driver.core.ConsistencyLevel consistencyLevel;
/**
* Construct a new {@link ReactiveCqlTemplate Note: The {@link ReactiveSessionFactory} has to be set before using the
@@ -132,6 +133,7 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* be {@literal null}.
*/
public ReactiveCqlTemplate(ReactiveSessionFactory reactiveSessionFactory) {
setSessionFactory(reactiveSessionFactory);
afterPropertiesSet();
}
@@ -145,13 +147,14 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* @see Statement#setConsistencyLevel(ConsistencyLevel)
* @see RetryPolicy
*/
public void setConsistencyLevel(ConsistencyLevel consistencyLevel) {
public void setConsistencyLevel(@Nullable ConsistencyLevel consistencyLevel) {
this.consistencyLevel = consistencyLevel;
}
/**
* @return the {@link ConsistencyLevel} specified for this {@link ReactiveCqlTemplate}.
*/
@Nullable
public ConsistencyLevel getConsistencyLevel() {
return consistencyLevel;
}
@@ -183,13 +186,14 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* @see Statement#setRetryPolicy(RetryPolicy)
* @see RetryPolicy
*/
public void setRetryPolicy(RetryPolicy retryPolicy) {
public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
}
/**
* @return the {@link RetryPolicy} specified for this {@link ReactiveCqlTemplate}.
*/
@Nullable
public RetryPolicy getRetryPolicy() {
return retryPolicy;
}
@@ -479,8 +483,9 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* @return an arbitrary result object, as returned by the {@link ReactiveResultSetExtractor}
* @throws DataAccessException if there is any problem
*/
public <T> Flux<T> query(ReactivePreparedStatementCreator psc, PreparedStatementBinder preparedStatementBinder,
ReactiveResultSetExtractor<T> rse) throws DataAccessException {
public <T> Flux<T> query(ReactivePreparedStatementCreator psc,
@Nullable PreparedStatementBinder preparedStatementBinder, ReactiveResultSetExtractor<T> rse)
throws DataAccessException {
Assert.notNull(psc, "ReactivePreparedStatementCreator must not be null");
Assert.notNull(rse, "ReactiveResultSetExtractor object must not be null");
@@ -506,7 +511,6 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
@Override
public <T> Flux<T> query(ReactivePreparedStatementCreator psc, ReactiveResultSetExtractor<T> rse)
throws DataAccessException {
return query(psc, null, rse);
}
@@ -514,9 +518,8 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* @see org.springframework.data.cassandra.core.cql.ReactiveCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ReactiveResultSetExtractor)
*/
@Override
public <T> Flux<T> query(String cql, PreparedStatementBinder psb, ReactiveResultSetExtractor<T> rse)
public <T> Flux<T> query(String cql, @Nullable PreparedStatementBinder psb, ReactiveResultSetExtractor<T> rse)
throws DataAccessException {
return query(new SimpleReactivePreparedStatementCreator(cql), psb, rse);
}
@@ -540,7 +543,8 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* @see org.springframework.data.cassandra.core.cql.ReactiveCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowMapper)
*/
@Override
public <T> Flux<T> query(String cql, PreparedStatementBinder psb, RowMapper<T> rowMapper) throws DataAccessException {
public <T> Flux<T> query(String cql, @Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper)
throws DataAccessException {
return query(cql, psb, new ReactiveRowMapperResultSetExtractor<>(rowMapper));
}
@@ -548,8 +552,8 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* @see org.springframework.data.cassandra.core.cql.ReactiveCqlOperations#query(org.springframework.data.cassandra.core.cql.ReactivePreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowMapper)
*/
@Override
public <T> Flux<T> query(ReactivePreparedStatementCreator psc, PreparedStatementBinder psb, RowMapper<T> rowMapper)
throws DataAccessException {
public <T> Flux<T> query(ReactivePreparedStatementCreator psc, @Nullable PreparedStatementBinder psb,
RowMapper<T> rowMapper) throws DataAccessException {
return query(psc, psb, new ReactiveRowMapperResultSetExtractor<>(rowMapper));
}
@@ -636,7 +640,7 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* @see org.springframework.data.cassandra.core.cql.ReactiveCqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder)
*/
@Override
public Mono<Boolean> execute(String cql, PreparedStatementBinder psb) throws DataAccessException {
public Mono<Boolean> execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException {
return query(new SimpleReactivePreparedStatementCreator(cql), psb, resultSet -> Mono.just(resultSet.wasApplied()))
.next();
}
@@ -699,7 +703,7 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* Create a reusable {@link Mono} given a {@link ReactiveStatementCallback} without exception translation.
*
* @param callback must not be {@literal null}.
* @return a reusable {@link Mono} wrapping the {@link ReactiveStatementCallback }.
* @return a reusable {@link Mono} wrapping the {@link ReactiveStatementCallback}.
*/
protected <T> Mono<T> createMono(Statement statement, ReactiveStatementCallback<T> callback) {
@@ -731,11 +735,11 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* Exception translation {@link Function} intended for {@link Mono#otherwise(Function)} usage.
*
* @param task readable text describing the task being attempted
* @param cql CQL query or update that caused the problem (may be {@code null})
* @param cql CQL query or update that caused the problem (may be {@literal null})
* @return the exception translation {@link Function}
* @see CqlProvider
*/
protected Function<Throwable, Throwable> translateException(String task, String cql) {
protected Function<Throwable, Throwable> translateException(String task, @Nullable String cql) {
return throwable -> throwable instanceof DriverException ? translate(task, cql, (DriverException) throwable)
: throwable;
}
@@ -828,17 +832,23 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
}
private ReactiveSession getSession() {
return getSessionFactory().getSession();
ReactiveSessionFactory sessionFactory = getSessionFactory();
Assert.state(sessionFactory != null, "SessionFactory is null");
return sessionFactory.getSession();
}
/**
* Determine CQL from potential provider object.
*
* @param cqlProvider object that's potentially a {@link CqlProvider}
* @return the CQL string, or {@code null}
* @return the CQL string, or {@literal null}
* @see CqlProvider
*/
private static String getCql(Object cqlProvider) {
@Nullable
private static String getCql(@Nullable Object cqlProvider) {
return Optional.ofNullable(cqlProvider) //
.filter(o -> o instanceof CqlProvider) //
@@ -847,7 +857,7 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
.orElse(null);
}
private class SimpleReactivePreparedStatementCreator implements ReactivePreparedStatementCreator, CqlProvider {
class SimpleReactivePreparedStatementCreator implements ReactivePreparedStatementCreator, CqlProvider {
private final String cql;

View File

@@ -16,6 +16,7 @@
package org.springframework.data.cassandra.core.cql;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.exceptions.DriverException;
@@ -52,5 +53,6 @@ public interface ResultSetExtractor<T> {
* there's no need to catch {@link DriverException})
* @throws DataAccessException in case of custom exceptions
*/
@Nullable
T extractData(ResultSet resultSet) throws DriverException, DataAccessException;
}

View File

@@ -29,7 +29,6 @@ import com.datastax.driver.core.exceptions.DriverException;
*
* @author David Webb
* @author Mark Paluch
* @param <T>
*/
public enum RingMemberHostMapper implements HostMapper<RingMember> {

View File

@@ -39,15 +39,15 @@ import com.datastax.driver.core.exceptions.DriverException;
public interface RowCallbackHandler {
/**
* Implementations must implement this method to process each row of data in the {@link ResultSet}. This method is
* only supposed to extract values of the current row.
* Implementations must implement this method to process each row of data in the
* {@link com.datastax.driver.core.ResultSet}. This method is only supposed to extract values of the current row.
* <p>
* Exactly what the implementation chooses to do is up to it: A trivial implementation might simply count rows, while
* another implementation might build an XML document.
*
* @param row the {@link Row} to process (pre-initialized for the current row).
* @throws DriverException if a {@link DriverException} is encountered getting column values (that is, there's no need
* to catch {@link DriverException})
* to catch {@link DriverException}).
*/
void processRow(Row row) throws DriverException;
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.cassandra.core.cql;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.exceptions.DriverException;
@@ -46,5 +48,6 @@ public interface RowMapper<T> {
* @throws DriverException if a {@link DriverException} is encountered getting column values (that is, there's no need
* to catch {@link DriverException})
*/
@Nullable
T mapRow(Row row, int rowNum) throws DriverException;
}

View File

@@ -19,6 +19,8 @@ import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.UUID;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.LocalDate;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.TupleValue;
@@ -44,10 +46,11 @@ public abstract class RowUtils {
*
* @param row is the {@link Row} holding the data
* @param index is the column index
* @param requiredType the required value type (may be {@code null})
* @param requiredType the required value type (may be {@literal null})
* @return the value object
*/
public static Object getRowValue(Row row, int index, Class<?> requiredType) {
@Nullable
public static Object getRowValue(Row row, int index, @Nullable Class<?> requiredType) {
if (requiredType == null) {
return row.getObject(index);

View File

@@ -47,7 +47,7 @@ public interface SessionCallback<T> {
* template.
*
* @param session active Cassandra Session, must not be {@literal null}.
* @return a result object, or {@code null} if none.
* @return a result object, or {@literal null} if none.
* @throws DriverException if thrown by a Session method, to be auto-converted to a {@link DataAccessException}.
* @throws DataAccessException in case of custom exceptions.
* @see CqlTemplate#queryForObject(String, Class)

View File

@@ -44,6 +44,7 @@ public class SimplePreparedStatementCreator implements PreparedStatementCreator,
public SimplePreparedStatementCreator(String cql) {
Assert.notNull(cql, "CQL is required to create a PreparedStatement");
this.cql = cql;
}

View File

@@ -16,6 +16,7 @@
package org.springframework.data.cassandra.core.cql;
import org.springframework.dao.TypeMismatchDataAccessException;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.NumberUtils;
@@ -41,7 +42,7 @@ import com.datastax.driver.core.exceptions.DriverException;
*/
public class SingleColumnRowMapper<T> implements RowMapper<T> {
private Class<?> requiredType;
private @Nullable Class<?> requiredType;
/**
* Create a new {@link SingleColumnRowMapper} for bean-style configuration.
@@ -119,13 +120,14 @@ public class SingleColumnRowMapper<T> implements RowMapper<T> {
*
* @param row is the {@link Row} holding the data, must not be {@literal null}.
* @param index is the column index
* @param requiredType the type that each result object is expected to match (or {@code null} if none specified).
* @param requiredType the type that each result object is expected to match (or {@literal null} if none specified).
* @return the Object value.
* @throws DriverException in case of extraction failure
* @see RowUtils#getRowValue(Row, int, Class)
* @see #getColumnValue(Row, int)
*/
protected Object getColumnValue(Row row, int index, Class<?> requiredType) throws DriverException {
@Nullable
protected Object getColumnValue(Row row, int index, @Nullable Class<?> requiredType) throws DriverException {
if (requiredType != null) {
return RowUtils.getRowValue(row, index, requiredType);
@@ -148,6 +150,7 @@ public class SingleColumnRowMapper<T> implements RowMapper<T> {
* @throws DriverException in case of extraction failure.
* @see RowUtils#getRowValue(Row, int, Class)
*/
@Nullable
protected Object getColumnValue(Row row, int index) {
return RowUtils.getRowValue(row, index, null);
}
@@ -160,8 +163,8 @@ public class SingleColumnRowMapper<T> implements RowMapper<T> {
* the value will be converted into a Number, either through number conversion or through String parsing (depending on
* the value type).
*
* @param value the column value as extracted from {@code getColumnValue()} (never {@code null})
* @param requiredType the type that each result object is expected to match (never {@code null})
* @param value the column value as extracted from {@code getColumnValue()} (never {@literal null})
* @param requiredType the type that each result object is expected to match (never {@literal null})
* @return the converted value
* @see #getColumnValue(Row, int, Class)
*/

View File

@@ -15,8 +15,12 @@
*/
package org.springframework.data.cassandra.core.cql;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.policies.RetryPolicy;
@@ -30,20 +34,19 @@ import com.datastax.driver.core.policies.RetryPolicy;
*/
public class WriteOptions extends QueryOptions {
private Integer ttl;
private static final WriteOptions EMPTY = new WriteOptionsBuilder().build();
/**
* Creates new {@link WriteOptions}.
*/
public WriteOptions() {}
private final Duration ttl;
/**
* Creates new {@link WriteOptions} for the given {@link ConsistencyLevel} and {@link RetryPolicy}.
*
* @param consistencyLevel the consistency level, may be {@literal null}.
* @param retryPolicy the retry policy, may be {@literal null}.
* @deprecated since 2.0, use {@link #builder()} or {@link #empty()}.
*/
public WriteOptions(ConsistencyLevel consistencyLevel, RetryPolicy retryPolicy) {
@Deprecated
public WriteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy) {
this(consistencyLevel, retryPolicy, null);
}
@@ -53,10 +56,32 @@ public class WriteOptions extends QueryOptions {
* @param consistencyLevel the consistency level, may be {@literal null}.
* @param retryPolicy the retry policy, may be {@literal null}.
* @param ttl the ttl, may be {@literal null}.
* @deprecated since 2.0, use {@link #builder()}.
*/
public WriteOptions(ConsistencyLevel consistencyLevel, RetryPolicy retryPolicy, Integer ttl) {
@Deprecated
public WriteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Integer ttl) {
super(consistencyLevel, retryPolicy);
setTtl(ttl);
this.ttl = ttl == null ? Duration.ofMillis(-1) : Duration.ofSeconds(ttl);
}
protected WriteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl) {
super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout);
this.ttl = ttl;
}
/**
* Create default {@link WriteOptions}.
*
* @return default {@link WriteOptions}.
* @since 2.0
*/
public static WriteOptions empty() {
return EMPTY;
}
/**
@@ -72,19 +97,10 @@ public class WriteOptions extends QueryOptions {
/**
* @return the time to live, if set.
*/
public Integer getTtl() {
public Duration getTtl() {
return this.ttl;
}
/**
* Sets the time to live for write operations.
*
* @param ttl the ttl to set.
*/
public void setTtl(Integer ttl) {
this.ttl = ttl;
}
/**
* Builder for {@link QueryOptions}.
*
@@ -93,7 +109,7 @@ public class WriteOptions extends QueryOptions {
*/
public static class WriteOptionsBuilder extends QueryOptionsBuilder {
private Integer ttl;
protected Duration ttl = Duration.ofMillis(-1);
protected WriteOptionsBuilder() {}
@@ -138,10 +154,16 @@ public class WriteOptions extends QueryOptions {
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long, java.util.concurrent.TimeUnit)
*/
@Override
@Deprecated
public WriteOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) {
return (WriteOptionsBuilder) super.readTimeout(readTimeout, timeUnit);
}
@Override
public WriteOptionsBuilder readTimeout(Duration readTimeout) {
return (WriteOptionsBuilder) super.readTimeout(readTimeout);
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#tracing(boolean)
@@ -161,13 +183,34 @@ public class WriteOptions extends QueryOptions {
}
/**
* Sets the time to live for write operations.
* Sets the time to live in seconds for write operations.
*
* @param ttl the time to live.
* @return {@code this} {@link WriteOptionsBuilder}
*/
public WriteOptionsBuilder ttl(int ttl) {
Assert.isTrue(ttl >= 0, "TTL must be greater than equal to zero");
this.ttl = Duration.ofSeconds(ttl);
return this;
}
/**
* Sets the time to live in seconds for write operations.
*
* @param ttl the time to live.
* @return {@code this} {@link WriteOptionsBuilder}
* @since 2.0
*/
public WriteOptionsBuilder ttl(Duration ttl) {
Assert.notNull(ttl, "TTL must not be null");
Assert.isTrue(!ttl.isNegative(), "TTL must be greater than equal to zero");
this.ttl = ttl;
return this;
}
@@ -177,17 +220,7 @@ public class WriteOptions extends QueryOptions {
* @return a new {@link WriteOptions} with the configured values
*/
public WriteOptions build() {
return applyOptions(new WriteOptions());
}
@Override
protected <T> T applyOptions(T queryOptions) {
WriteOptions writeOptions = (WriteOptions) queryOptions;
writeOptions.setTtl(this.ttl);
return super.applyOptions(queryOptions);
return new WriteOptions(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl);
}
}
}

View File

@@ -19,6 +19,7 @@ import java.util.List;
import java.util.Map;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;
import com.datastax.driver.core.ResultSet;
@@ -59,6 +60,7 @@ public abstract class AbstractResultSetConverter<T> implements Converter<ResultS
/**
* @return surrogate value if the {@link ResultSet} is {@literal null}.
*/
@Nullable
protected T getNullResultSetValue() {
return null;
}
@@ -66,6 +68,7 @@ public abstract class AbstractResultSetConverter<T> implements Converter<ResultS
/**
* @return surrogate value if the {@link ResultSet} is {@link ResultSet#isExhausted() exhausted}.
*/
@Nullable
protected T getExhaustedResultSetValue() {
return null;
}
@@ -73,16 +76,16 @@ public abstract class AbstractResultSetConverter<T> implements Converter<ResultS
@Override
public T convert(ResultSet source) {
if (source == null) {
return getNullResultSetValue();
}
if (source.isExhausted()) {
return getExhaustedResultSetValue();
}
List<Map<String, Object>> list = converter.convert(source);
if (list == null) {
return getNullResultSetValue();
}
if (list.size() == 1) {
Map<String, Object> map = list.get(0);
@@ -97,8 +100,9 @@ public abstract class AbstractResultSetConverter<T> implements Converter<ResultS
* or throws {@link IllegalArgumentException}. This default implementation simply throws.
*/
protected T doConvertResultSet(List<Map<String, Object>> resultSet) {
doThrow("result set");
return null;
throw new IllegalArgumentException(
String.format("Cannot convert %s to desired type [%s]", "result set", getType().getName()));
}
/**
@@ -106,12 +110,8 @@ public abstract class AbstractResultSetConverter<T> implements Converter<ResultS
* {@link IllegalArgumentException}. This default implementation simply throws.
*/
protected T doConvertSingleRow(Map<String, Object> row) {
doThrow("row");
return null;
}
void doThrow(String string) {
throw new IllegalArgumentException(
String.format("Cannot convert %s to desired type [%s]", string, getType().getName()));
String.format("Cannot convert %s to desired type [%s]", "row", getType().getName()));
}
}

View File

@@ -51,10 +51,6 @@ public class ResultSetToArrayConverter implements Converter<ResultSet, Object[]>
@Override
public Object[] convert(ResultSet resultSet) {
if (resultSet == null) {
return null;
}
List<Object[]> list = new ArrayList<>();
for (Row row : resultSet) {
list.add(rowConverter.convert(row));

View File

@@ -37,7 +37,8 @@ public class ResultSetToByteBufferConverter extends AbstractResultSetConverter<B
protected ByteBuffer doConvertSingleValue(Object object) {
if (!(object instanceof ByteBuffer)) {
doThrow("value");
throw new IllegalArgumentException(
String.format("Cannot convert %s to desired type [%s]", "value", getType().getName()));
}
return (ByteBuffer) object;

View File

@@ -59,10 +59,6 @@ public class ResultSetToListConverter implements Converter<ResultSet, List<Map<S
@Override
public List<Map<String, Object>> convert(ResultSet resultSet) {
if (resultSet == null) {
return null;
}
List<Map<String, Object>> list = new ArrayList<>();
for (Row row : resultSet) {
list.add(rowConverter.convert(row));

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.core.cql.converter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -39,11 +39,7 @@ public class ResultSetToListOfStringConverter extends AbstractResultSetConverter
*/
@Override
protected List<String> doConvertSingleValue(Object object) {
List<String> list = new ArrayList<>();
list.add(object == null ? null : object.toString());
return list;
return Collections.singletonList(object.toString());
}
/* (non-Javadoc)

View File

@@ -36,7 +36,7 @@ public class ResultSetToStringConverter extends AbstractResultSetConverter<Strin
*/
@Override
protected String doConvertSingleValue(Object object) {
return object == null ? null : object.toString();
return object.toString();
}
/* (non-Javadoc)

View File

@@ -44,10 +44,6 @@ public enum RowToListConverter implements Converter<Row, List<Object>> {
@Override
public List<Object> convert(Row row) {
if (row == null) {
return null;
}
ColumnDefinitions cols = row.getColumnDefinitions();
return cols.asList().stream() //
.map(Definition::getName).map(name -> row.isNull(name) ? null : row.getObject(name)) //

View File

@@ -44,10 +44,6 @@ public enum RowToMapConverter implements Converter<Row, Map<String, Object>> {
@Override
public Map<String, Object> convert(Row row) {
if (row == null) {
return null;
}
ColumnDefinitions cols = row.getColumnDefinitions();
Map<String, Object> map = new HashMap<>(cols.size());

View File

@@ -1,4 +1,7 @@
/**
* CQL specific converters.
*/
@NonNullApi
package org.springframework.data.cassandra.core.cql.converter;
import org.springframework.lang.NonNullApi;

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*;
import org.springframework.data.cassandra.core.cql.keyspace.AddColumnSpecification;
/**
@@ -39,7 +37,7 @@ public class AddColumnCqlGenerator extends ColumnChangeCqlGenerator<AddColumnSpe
*/
@Override
public StringBuilder toCql(StringBuilder cql) {
return noNull(cql).append("ADD ").append(spec().getName()).append(' ')
return cql.append("ADD ").append(spec().getName()).append(' ')
.append(spec().getType().asFunctionParameterString());
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*;
import org.springframework.data.cassandra.core.cql.keyspace.AlterColumnSpecification;
/**
@@ -33,7 +31,7 @@ public class AlterColumnCqlGenerator extends ColumnChangeCqlGenerator<AlterColum
}
public StringBuilder toCql(StringBuilder cql) {
return noNull(cql).append("ALTER ").append(spec().getName()).append(" TYPE ")
return cql.append("ALTER ").append(spec().getName()).append(" TYPE ")
.append(spec().getType().asFunctionParameterString());
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*;
import java.util.Map;
import org.springframework.data.cassandra.core.cql.keyspace.AlterKeyspaceSpecification;
@@ -29,17 +27,16 @@ import org.springframework.data.cassandra.core.cql.keyspace.Option;
*/
public class AlterKeyspaceCqlGenerator extends KeyspaceOptionsCqlGenerator<AlterKeyspaceSpecification> {
public static String toCql(AlterKeyspaceSpecification specification) {
return new AlterKeyspaceCqlGenerator(specification).toCql();
}
public AlterKeyspaceCqlGenerator(AlterKeyspaceSpecification specification) {
super(specification);
}
public static String toCql(AlterKeyspaceSpecification specification) {
return new AlterKeyspaceCqlGenerator(specification).toCql();
}
@Override
public StringBuilder toCql(StringBuilder cql) {
cql = noNull(cql);
preambleCql(cql);
optionsCql(cql);
@@ -49,13 +46,12 @@ public class AlterKeyspaceCqlGenerator extends KeyspaceOptionsCqlGenerator<Alter
return cql;
}
protected StringBuilder preambleCql(StringBuilder cql) {
return noNull(cql).append("ALTER KEYSPACE ").append(spec().getName()).append(" ");
private void preambleCql(StringBuilder cql) {
cql.append("ALTER KEYSPACE ").append(spec().getName()).append(" ");
}
@SuppressWarnings("unchecked")
protected StringBuilder optionsCql(StringBuilder cql) {
cql = noNull(cql);
private void optionsCql(StringBuilder cql) {
// begin options clause
Map<String, Object> options = spec().getOptions();
@@ -97,7 +93,5 @@ public class AlterKeyspaceCqlGenerator extends KeyspaceOptionsCqlGenerator<Alter
}
}
// end options
return cql;
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*;
import java.util.Map;
import org.springframework.data.cassandra.core.cql.keyspace.AddColumnSpecification;
@@ -38,6 +36,13 @@ import org.springframework.data.cassandra.core.cql.keyspace.TableOption;
*/
public class AlterTableCqlGenerator extends TableOptionsCqlGenerator<AlterTableSpecification> {
/**
* Create a new {@literal {@link AlterTableCqlGenerator}. @param specification must not be {@literal null}.
*/
public AlterTableCqlGenerator(AlterTableSpecification specification) {
super(specification);
}
/**
* Generates a CQL statement from the given {@code specification}.
*
@@ -48,18 +53,8 @@ public class AlterTableCqlGenerator extends TableOptionsCqlGenerator<AlterTableS
return new AlterTableCqlGenerator(specification).toCql();
}
/**
* Create a new {@literal {@link AlterTableCqlGenerator}.
*
* @param specification must not be {@literal null}.
*/
public AlterTableCqlGenerator(AlterTableSpecification specification) {
super(specification);
}
@Override
public StringBuilder toCql(StringBuilder cql) {
cql = noNull(cql);
preambleCql(cql);
@@ -78,12 +73,11 @@ public class AlterTableCqlGenerator extends TableOptionsCqlGenerator<AlterTableS
return cql;
}
protected StringBuilder preambleCql(StringBuilder cql) {
return noNull(cql).append("ALTER TABLE ").append(spec().getName());
private void preambleCql(StringBuilder cql) {
cql.append("ALTER TABLE ").append(spec().getName());
}
protected StringBuilder changesCql(StringBuilder cql) {
cql = noNull(cql);
private void changesCql(StringBuilder cql) {
boolean first = true;
@@ -96,10 +90,9 @@ public class AlterTableCqlGenerator extends TableOptionsCqlGenerator<AlterTableS
getCqlGeneratorFor(change).toCql(cql);
}
return cql;
}
protected ColumnChangeCqlGenerator<?> getCqlGeneratorFor(ColumnChangeSpecification change) {
private ColumnChangeCqlGenerator<?> getCqlGeneratorFor(ColumnChangeSpecification change) {
if (change instanceof AddColumnSpecification) {
return new AddColumnCqlGenerator((AddColumnSpecification) change);
@@ -121,14 +114,12 @@ public class AlterTableCqlGenerator extends TableOptionsCqlGenerator<AlterTableS
}
@SuppressWarnings("unchecked")
protected StringBuilder optionsCql(StringBuilder cql) {
cql = noNull(cql);
private void optionsCql(StringBuilder cql) {
Map<String, Object> options = spec().getOptions();
if (options == null || options.isEmpty()) {
return cql;
if (options.isEmpty()) {
return;
}
cql.append("WITH ");
@@ -169,7 +160,5 @@ public class AlterTableCqlGenerator extends TableOptionsCqlGenerator<AlterTableS
// else just use value as string
cql.append(value.toString());
}
return cql;
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*;
import org.springframework.data.cassandra.core.cql.keyspace.AddColumnSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.AlterColumnSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.AlterUserTypeSpecification;
@@ -37,10 +35,6 @@ import org.springframework.util.Assert;
*/
public class AlterUserTypeCqlGenerator extends UserTypeNameCqlGenerator<AlterUserTypeSpecification> {
public static String toCql(AlterUserTypeSpecification specification) {
return new AlterUserTypeCqlGenerator(specification).toCql();
}
/**
* Create a new {@link AlterUserTypeCqlGenerator} for a {@link AlterUserTypeSpecification}.
*
@@ -50,6 +44,10 @@ public class AlterUserTypeCqlGenerator extends UserTypeNameCqlGenerator<AlterUse
super(specification);
}
public static String toCql(AlterUserTypeSpecification specification) {
return new AlterUserTypeCqlGenerator(specification).toCql();
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.generator.UserTypeNameCqlGenerator#toCql(java.lang.StringBuilder)
@@ -66,11 +64,10 @@ public class AlterUserTypeCqlGenerator extends UserTypeNameCqlGenerator<AlterUse
}
private StringBuilder preambleCql(StringBuilder cql) {
return noNull(cql).append("ALTER TYPE ").append(spec().getName()).append(' ');
return cql.append("ALTER TYPE ").append(spec().getName()).append(' ');
}
private StringBuilder changesCql(StringBuilder cql) {
cql = noNull(cql);
boolean first = true;
boolean lastChangeWasRename = false;

View File

@@ -31,7 +31,9 @@ public abstract class ColumnChangeCqlGenerator<T extends ColumnChangeSpecificati
private ColumnChangeSpecification specification;
public ColumnChangeCqlGenerator(ColumnChangeSpecification specification) {
setSpecification(specification);
Assert.notNull(specification, "ColumnChangeSpecification must not be null");
this.specification = specification;
}
protected void setSpecification(ColumnChangeSpecification specification) {

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.noNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -35,19 +33,17 @@ import org.springframework.util.StringUtils;
*/
public class CreateIndexCqlGenerator extends IndexNameCqlGenerator<CreateIndexSpecification> {
public static String toCql(CreateIndexSpecification specification) {
return new CreateIndexCqlGenerator(specification).toCql();
}
public CreateIndexCqlGenerator(CreateIndexSpecification specification) {
super(specification);
}
public static String toCql(CreateIndexSpecification specification) {
return new CreateIndexCqlGenerator(specification).toCql();
}
@Override
public StringBuilder toCql(StringBuilder cql) {
cql = noNull(cql);
cql.append("CREATE").append(spec().isCustom() ? " CUSTOM" : "").append(" INDEX")
.append(spec().getIfNotExists() ? " IF NOT EXISTS" : "");

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*;
import java.util.Map;
import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
@@ -30,21 +28,19 @@ import org.springframework.data.cassandra.core.cql.keyspace.Option;
* @author Matthew T. Adams
* @author Alex Shvid
*/
public class CreateKeyspaceCqlGenerator extends KeyspaceCqlGenerator<CreateKeyspaceSpecification> {
public static String toCql(CreateKeyspaceSpecification specification) {
return new CreateKeyspaceCqlGenerator(specification).toCql();
}
public class CreateKeyspaceCqlGenerator extends KeyspaceOptionsCqlGenerator<CreateKeyspaceSpecification> {
public CreateKeyspaceCqlGenerator(CreateKeyspaceSpecification specification) {
super(specification);
}
public static String toCql(CreateKeyspaceSpecification specification) {
return new CreateKeyspaceCqlGenerator(specification).toCql();
}
@Override
public StringBuilder toCql(StringBuilder cql) {
cql = noNull(cql);
preambleCql(cql);
optionsCql(cql);
@@ -53,14 +49,13 @@ public class CreateKeyspaceCqlGenerator extends KeyspaceCqlGenerator<CreateKeysp
return cql;
}
protected StringBuilder preambleCql(StringBuilder cql) {
return noNull(cql).append("CREATE KEYSPACE ").append(spec().getIfNotExists() ? "IF NOT EXISTS " : "")
private void preambleCql(StringBuilder cql) {
cql.append("CREATE KEYSPACE ").append(spec().getIfNotExists() ? "IF NOT EXISTS " : "")
.append(spec().getName());
}
@SuppressWarnings("unchecked")
protected StringBuilder optionsCql(StringBuilder cql) {
cql = noNull(cql);
private void optionsCql(StringBuilder cql) {
cql.append(" ");
@@ -115,7 +110,5 @@ public class CreateKeyspaceCqlGenerator extends KeyspaceCqlGenerator<CreateKeysp
}
}
// end options
return cql;
}
}

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*;
import static org.springframework.data.cassandra.core.cql.PrimaryKeyType.*;
import java.util.ArrayList;
@@ -25,6 +24,8 @@ import java.util.Map;
import org.springframework.data.cassandra.core.cql.keyspace.ColumnSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.Option;
import org.springframework.data.cassandra.core.cql.keyspace.TableSpecification;
import org.springframework.util.StringUtils;
/**
* CQL generator for generating a {@code CREATE TABLE} statement.
@@ -32,21 +33,24 @@ import org.springframework.data.cassandra.core.cql.keyspace.Option;
* @author Matthew T. Adams
* @author Alex Shvid
*/
public class CreateTableCqlGenerator extends TableCqlGenerator<CreateTableSpecification> {
public static String toCql(CreateTableSpecification specification) {
return new CreateTableCqlGenerator(specification).toCql();
}
public class CreateTableCqlGenerator extends TableOptionsCqlGenerator<TableSpecification<CreateTableSpecification>> {
public CreateTableCqlGenerator(CreateTableSpecification specification) {
super(specification);
}
public static String toCql(CreateTableSpecification specification) {
return new CreateTableCqlGenerator(specification).toCql();
}
@Override
protected CreateTableSpecification spec() {
return (CreateTableSpecification) super.spec();
}
@Override
public StringBuilder toCql(StringBuilder cql) {
cql = noNull(cql);
preambleCql(cql);
columnsAndOptionsCql(cql);
@@ -55,15 +59,12 @@ public class CreateTableCqlGenerator extends TableCqlGenerator<CreateTableSpecif
return cql;
}
protected StringBuilder preambleCql(StringBuilder cql) {
return noNull(cql).append("CREATE TABLE ").append(spec().getIfNotExists() ? "IF NOT EXISTS " : "")
.append(spec().getName());
private void preambleCql(StringBuilder cql) {
cql.append("CREATE TABLE ").append(spec().getIfNotExists() ? "IF NOT EXISTS " : "").append(spec().getName());
}
@SuppressWarnings("unchecked")
protected StringBuilder columnsAndOptionsCql(StringBuilder cql) {
cql = noNull(cql);
private void columnsAndOptionsCql(StringBuilder cql) {
// begin columns
cql.append(" (");
@@ -112,17 +113,18 @@ public class CreateTableCqlGenerator extends TableCqlGenerator<CreateTableSpecif
// begin option clause
Map<String, Object> options = spec().getOptions();
if (ordering != null || !options.isEmpty()) {
if (!options.isEmpty()) {
// option preamble
boolean first = true;
cql.append(" WITH ");
// end option preamble
if (ordering != null) {
if (StringUtils.hasText(ordering)) {
cql.append(ordering);
first = false;
}
if (!options.isEmpty()) {
for (String name : options.keySet()) {
// append AND if we're not on first option
@@ -153,17 +155,16 @@ public class CreateTableCqlGenerator extends TableCqlGenerator<CreateTableSpecif
}
}
// end options
return cql;
}
private static StringBuilder createOrderingClause(List<ColumnSpecification> columns) {
StringBuilder ordering = null;
StringBuilder ordering = new StringBuilder();
boolean first = true;
for (ColumnSpecification col : columns) {
if (col.getOrdering() != null) { // then ordering specified
if (ordering == null) { // then initialize ordering clause
if (StringUtils.isEmpty(ordering)) { // then initialize ordering clause
ordering = new StringBuilder().append("CLUSTERING ORDER BY (");
}
if (first) {
@@ -174,9 +175,11 @@ public class CreateTableCqlGenerator extends TableCqlGenerator<CreateTableSpecif
ordering.append(col.getName()).append(" ").append(col.getOrdering().cql());
}
}
if (ordering != null) { // then end ordering option
if (StringUtils.hasText(ordering)) { // then end ordering option
ordering.append(")");
}
return ordering;
}
@@ -192,7 +195,5 @@ public class CreateTableCqlGenerator extends TableCqlGenerator<CreateTableSpecif
str.append(col.getName());
}
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.noNull;
import org.springframework.data.cassandra.core.cql.keyspace.CreateUserTypeSpecification;
import org.springframework.data.cassandra.core.cql.keyspace.FieldSpecification;
import org.springframework.util.Assert;
@@ -31,10 +29,6 @@ import org.springframework.util.Assert;
*/
public class CreateUserTypeCqlGenerator extends UserTypeNameCqlGenerator<CreateUserTypeSpecification> {
public static String toCql(CreateUserTypeSpecification specification) {
return new CreateUserTypeCqlGenerator(specification).toCql();
}
/**
* Create a new {@link CreateUserTypeCqlGenerator} for a given {@link CreateUserTypeSpecification}.
*
@@ -44,6 +38,10 @@ public class CreateUserTypeCqlGenerator extends UserTypeNameCqlGenerator<CreateU
super(specification);
}
public static String toCql(CreateUserTypeSpecification specification) {
return new CreateUserTypeCqlGenerator(specification).toCql();
}
/*
* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.generator.UserTypeNameCqlGenerator#toCql(java.lang.StringBuilder)
@@ -61,14 +59,12 @@ public class CreateUserTypeCqlGenerator extends UserTypeNameCqlGenerator<CreateU
private StringBuilder preambleCql(StringBuilder cql) {
return noNull(cql).append("CREATE TYPE ").append(spec().getIfNotExists() ? "IF NOT EXISTS " : "")
return cql.append("CREATE TYPE ").append(spec().getIfNotExists() ? "IF NOT EXISTS " : "")
.append(spec().getName());
}
private StringBuilder columns(StringBuilder cql) {
cql = noNull(cql);
// begin columns
cql.append(" (");

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*;
import org.springframework.data.cassandra.core.cql.keyspace.DropColumnSpecification;
/**
@@ -34,6 +32,6 @@ public class DropColumnCqlGenerator extends ColumnChangeCqlGenerator<DropColumnS
}
public StringBuilder toCql(StringBuilder cql) {
return noNull(cql).append("DROP ").append(spec().getName());
return cql.append("DROP ").append(spec().getName());
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.cql.generator;
import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*;
import org.springframework.data.cassandra.core.cql.keyspace.DropIndexSpecification;
/**
@@ -37,7 +35,7 @@ public class DropIndexCqlGenerator extends IndexNameCqlGenerator<DropIndexSpecif
@Override
public StringBuilder toCql(StringBuilder cql) {
return noNull(cql).append("DROP INDEX ")
return cql.append("DROP INDEX ")
// .append(spec().getIfExists() ? "IF EXISTS " : "")
.append(spec().getName()).append(";");
}

Some files were not shown because too many files have changed in this diff Show More