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/template/async/ObjectListener.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/template/async/ObjectListener.java
index 2d17645d0..af706bd27 100644
--- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/template/async/ObjectListener.java
+++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/template/async/ObjectListener.java
@@ -3,10 +3,10 @@ package org.springframework.cassandra.test.integration.core.template.async;
import org.springframework.cassandra.core.QueryForObjectListener;
import org.springframework.cassandra.test.unit.support.TestListener;
-class ObjectListener extends TestListener implements QueryForObjectListener {
+public class ObjectListener extends TestListener implements QueryForObjectListener {
- T result;
- Exception exception;
+ public T result;
+ public Exception exception;
@Override
public void onQueryComplete(T result) {
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 d0b7cc895..396544509 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
@@ -1033,6 +1033,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/template/async/AsynchronousCassandraTemplateTest.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/async/AsynchronousCassandraTemplateTest.java
index e48a5593b..3fd3c4056 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/async/AsynchronousCassandraTemplateTest.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/async/AsynchronousCassandraTemplateTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2014 the original author or authors
+ * Copyright 2013-2016 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,9 @@
*/
package org.springframework.data.cassandra.test.integration.template.async;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-import static org.springframework.data.cassandra.repository.support.BasicMapId.id;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+import static org.springframework.data.cassandra.repository.support.BasicMapId.*;
import java.util.Collection;
import java.util.Random;
@@ -35,6 +34,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.template.async.ObjectListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.CassandraTemplate;
@@ -53,11 +53,46 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* Asynchronous {@link CassandraTemplate} tests.
*
* @author Matthew T. Adams
+ * @author Mark Paluch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class AsynchronousCassandraTemplateTest extends AbstractSpringDataEmbeddedCassandraIntegrationTest {
+ /**
+ * @see DATACASS-287
+ */
+ @Test(timeout = 10000)
+ public void shouldSelectOneAsynchronously() throws Exception {
+
+ Thing thing = Thing.random();
+ template.insert(thing);
+
+ ObjectListener objectListener = new ObjectListener();
+ String cql = String.format("SELECT * from thing where stuff = '%s'", thing.stuff);
+
+ template.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());
+
+ template.selectOneAsynchronously(cql, Thing.class, objectListener);
+ objectListener.await();
+
+ assertThat(objectListener.result, is(nullValue()));
+ }
+
@Configuration
public static class Config extends IntegrationTestConfig {
}