diff --git a/spring-cql/src/main/java/org/springframework/cassandra/core/QueryForObjectListener.java b/spring-cql/src/main/java/org/springframework/cassandra/core/QueryForObjectListener.java
index d4c1c8cb9..b1b9ab021 100644
--- a/spring-cql/src/main/java/org/springframework/cassandra/core/QueryForObjectListener.java
+++ b/spring-cql/src/main/java/org/springframework/cassandra/core/QueryForObjectListener.java
@@ -1,22 +1,42 @@
+/*
+ * Copyright 2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.springframework.cassandra.core;
import com.datastax.driver.core.ResultSet;
/**
- * Listener used to receive asynchronous results expected as an object of type T.
+ * Listener used to receive asynchronous results expected as an object of type T or an {@link Exception}.
*
* @author Matthew T. Adams
+ * @author Mark Paluch
* @param
*/
public interface QueryForObjectListener {
/**
* Called upon query completion.
+ *
+ * @param result the result, can be {@literal null} for empty single-record results.
*/
void onQueryComplete(T result);
/**
* Called if an exception is raised while getting or converting the {@link ResultSet}.
+ *
+ * @param ex the exception that triggered the failure, never {@link null}.
*/
- void onException(Exception x);
+ void onException(Exception ex);
}
diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/async/ObjectListener.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/async/ObjectListener.java
index cf02c30af..1faaf14ba 100644
--- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/async/ObjectListener.java
+++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/async/ObjectListener.java
@@ -22,19 +22,21 @@ import org.springframework.cassandra.support.TestListener;
* @author Matthew T. Adams
* @author David Webb
*/
-class ObjectListener extends TestListener implements QueryForObjectListener {
+public class ObjectListener extends TestListener implements QueryForObjectListener {
- T result;
- Exception exception;
+ public volatile T result;
+ public volatile Exception exception;
@Override
public void onQueryComplete(T result) {
+
this.result = result;
countDown();
}
@Override
public void onException(Exception x) {
+
this.exception = x;
countDown();
}
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java
index 23fe62e4c..a90c2cbf5 100644
--- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java
@@ -1068,6 +1068,9 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
}
listener.onQueryComplete(result);
}
+ else{
+ listener.onQueryComplete(null);
+ }
} catch (Exception e) {
listener.onException(translateExceptionIfPossible(e));
}
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/core/AsynchronousCassandraTemplateIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/core/AsynchronousCassandraTemplateIntegrationTests.java
index f62a95fc6..676e0c982 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/core/AsynchronousCassandraTemplateIntegrationTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/core/AsynchronousCassandraTemplateIntegrationTests.java
@@ -15,6 +15,7 @@
*/
package org.springframework.data.cassandra.test.integration.core;
+import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import static org.springframework.data.cassandra.repository.support.BasicMapId.*;
@@ -34,6 +35,7 @@ import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.cassandra.core.RetryPolicy;
import org.springframework.cassandra.core.WriteOptions;
import org.springframework.cassandra.support.exception.CassandraConnectionFailureException;
+import org.springframework.cassandra.test.integration.core.async.ObjectListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.CassandraTemplate;
@@ -199,6 +201,40 @@ public class AsynchronousCassandraTemplateIntegrationTests extends AbstractSprin
fail("should've thrown CancellationException");
}
+ /**
+ * @see DATACASS-287
+ */
+ @Test(timeout = 10000)
+ public void shouldSelectOneAsynchronously() throws Exception {
+
+ Thing thing = Thing.random();
+ cassandraOperations.insert(thing);
+
+ ObjectListener objectListener = new ObjectListener();
+ String cql = String.format("SELECT * from thing where stuff = '%s'", thing.stuff);
+
+ cassandraOperations.selectOneAsynchronously(cql, Thing.class, objectListener);
+ objectListener.await();
+
+ assertThat(objectListener.result, is(notNullValue()));
+ assertThat(objectListener.result.stuff, is(equalTo(thing.stuff)));
+ }
+
+ /**
+ * @see DATACASS-287
+ */
+ @Test(timeout = 10000)
+ public void shouldSelectOneAsynchronouslyIfObjectIsAbsent() throws Exception {
+
+ ObjectListener objectListener = new ObjectListener();
+ String cql = String.format("SELECT * from thing where stuff = '%s'", UUID.randomUUID());
+
+ cassandraOperations.selectOneAsynchronously(cql, Thing.class, objectListener);
+ objectListener.await();
+
+ assertThat(objectListener.result, is(nullValue()));
+ }
+
@Configuration
public static class Config extends IntegrationTestConfig {}