From 23b688a5eb6c1ad4dd7db12f8daee89667c4afc2 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 3 Jun 2016 14:20:06 +0200 Subject: [PATCH] DATACASS-287 - Call QueryForObjectListener for absent singular responses. QueryForObjectListener is now called passing null for absent responses when querying for one single object. Original pull request: #63. --- .../core/QueryForObjectListener.java | 24 +++++++++- .../core/template/async/ObjectListener.java | 6 +-- .../cassandra/core/CassandraTemplate.java | 3 ++ .../AsynchronousCassandraTemplateTest.java | 45 ++++++++++++++++--- 4 files changed, 68 insertions(+), 10 deletions(-) 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 { }