diff --git a/src/integration/java/org/springframework/data/couchbase/repository/PageAndSliceTests.java b/src/integration/java/org/springframework/data/couchbase/repository/PageAndSliceTests.java index c773c0c6..d9031561 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/PageAndSliceTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/PageAndSliceTests.java @@ -67,7 +67,7 @@ public class PageAndSliceTests { assertEquals(10, page3.getNumberOfElements()); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = UnsupportedOperationException.class) public void shouldThrowWhenPageableIsNullInPageQuery() { repository.findByAgeGreaterThan(9, null); } @@ -86,7 +86,7 @@ public class PageAndSliceTests { assertEquals(9, allMatching.size()); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = UnsupportedOperationException.class) public void shouldThrowWhenPageableIsNullSliceQuery() { repository.findByAgeLessThan(9, null); } diff --git a/src/integration/java/org/springframework/data/couchbase/repository/QueryDerivationConversionTests.java b/src/integration/java/org/springframework/data/couchbase/repository/QueryDerivationConversionTests.java index 52f3d829..4bcd9e28 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/QueryDerivationConversionTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/QueryDerivationConversionTests.java @@ -2,10 +2,12 @@ package org.springframework.data.couchbase.repository; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.Optional; import com.couchbase.client.java.Bucket; import com.couchbase.client.java.document.JsonDocument; @@ -25,6 +27,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Simon Baslé + * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = IntegrationTestApplicationConfig.class) @@ -50,9 +53,8 @@ public class QueryDerivationConversionTests { @Test public void testConvertsDateParameterInN1qlQuery() { - Party partyApril = repository.findOne("testparty-3"); - assertNotNull(partyApril); - System.out.println(partyApril); + Optional partyApril = repository.findOne("testparty-3"); + assertTrue(partyApril.isPresent()); Calendar cal = Calendar.getInstance(); cal.clear(); diff --git a/src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java b/src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java index b333cde2..3bbee552 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2017 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. @@ -49,6 +49,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; @@ -56,6 +57,7 @@ import static org.junit.Assert.*; /** * @author Michael Nitschinger + * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = IntegrationTestApplicationConfig.class) @@ -97,14 +99,18 @@ public class SimpleCouchbaseRepositoryTests { User instance = new User(key, "foobar", 22); repository.save(instance); - User found = repository.findOne(key); - assertEquals(instance.getKey(), found.getKey()); - assertEquals(instance.getUsername(), found.getUsername()); + Optional found = repository.findOne(key); + assertTrue(found.isPresent()); - assertTrue(repository.exists(key)); - repository.delete(found); + found.ifPresent(actual -> { + assertEquals(instance.getKey(), actual.getKey()); + assertEquals(instance.getUsername(), actual.getUsername()); - assertNull(repository.findOne(key)); + assertTrue(repository.exists(key)); + repository.delete(actual); + }); + + assertFalse(repository.findOne(key).isPresent()); assertFalse(repository.exists(key)); } @@ -214,20 +220,26 @@ public class SimpleCouchbaseRepositoryTests { versionedDataRepository.save(initial); assertNotEquals(0L, initial.version); - VersionedData fetch1 = versionedDataRepository.findOne(key); - assertNotSame(initial, fetch1); - assertEquals(fetch1.version, initial.version); + Optional fetch1 = versionedDataRepository.findOne(key); + + assertTrue(fetch1.isPresent()); + fetch1.ifPresent(actual -> { + assertNotSame(initial, actual); + assertEquals(actual.version, initial.version); + }); + + VersionedData versionedData = fetch1.get(); JsonDocument bypass = client.get(key); bypass.content().put("data", "BBBB"); JsonDocument bypassed = client.upsert(bypass); - assertNotEquals(bypassed.cas(), fetch1.version); + assertNotEquals(bypassed.cas(), versionedData.version); System.out.println(bypassed.cas()); try { - fetch1.setData("ZZZZ"); - versionedDataRepository.save(fetch1); + versionedData.setData("ZZZZ"); + versionedDataRepository.save(versionedData); fail("Expected CAS failure"); } catch (OptimisticLockingFailureException e) { //success @@ -255,7 +267,7 @@ public class SimpleCouchbaseRepositoryTests { boolean updated = false; while(!updated) { long counterValue = counter.incrementAndGet(); - VersionedData messageData = versionedDataRepository.findOne(key); + VersionedData messageData = versionedDataRepository.findOne(key).get(); messageData.data = "value-" + counterValue; try { versionedDataRepository.save(messageData); @@ -269,7 +281,7 @@ public class SimpleCouchbaseRepositoryTests { }; AsyncUtils.executeConcurrently(5, task); - assertNotEquals(initial.data, versionedDataRepository.findOne(key).data); + assertNotEquals(initial.data, versionedDataRepository.findOne(key).get().data); assertEquals(5, updatedCounter.intValue()); } diff --git a/src/integration/java/org/springframework/data/couchbase/repository/auditing/AuditedAuditorAware.java b/src/integration/java/org/springframework/data/couchbase/repository/auditing/AuditedAuditorAware.java index 07812561..c8e3b9f6 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/auditing/AuditedAuditorAware.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/auditing/AuditedAuditorAware.java @@ -1,18 +1,19 @@ package org.springframework.data.couchbase.repository.auditing; import org.springframework.data.domain.AuditorAware; -import org.springframework.stereotype.Component; + +import java.util.Optional; public class AuditedAuditorAware implements AuditorAware { - private String auditor = "auditor"; + private Optional auditor = Optional.of("auditor"); @Override - public String getCurrentAuditor() { + public Optional getCurrentAuditor() { return auditor; } public void setAuditor(String auditor) { - this.auditor = auditor; + this.auditor = Optional.of(auditor); } } diff --git a/src/integration/java/org/springframework/data/couchbase/repository/auditing/AuditingTests.java b/src/integration/java/org/springframework/data/couchbase/repository/auditing/AuditingTests.java index 22d63e04..04812c2e 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/auditing/AuditingTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/auditing/AuditingTests.java @@ -3,19 +3,19 @@ package org.springframework.data.couchbase.repository.auditing; import static org.junit.Assert.*; import java.util.Date; +import java.util.Optional; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataRetrievalFailureException; -import org.springframework.data.couchbase.repository.CouchbaseRepository; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Simon Baslé + * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = AuditedApplicationConfig.class) @@ -42,20 +42,24 @@ public class AuditingTests { auditorAware.setAuditor("auditor"); repository.save(item); - AuditedItem persisted = repository.findOne(KEY); + Optional persisted = repository.findOne(KEY); - assertNotNull("expected entity to be persisted", persisted); - assertNotNull("expected creation date audit trail", persisted.getCreationDate()); - assertEquals("expected creation user audit trail", "auditor", persisted.getCreator()); + assertTrue(persisted.isPresent()); - assertTrue("creation date is too early", persisted.getCreationDate().after(start)); - assertTrue("creation date is too late", persisted.getCreationDate().before(new Date())); + persisted.ifPresent(actual -> { - assertNull("expected modification date to be empty", persisted.getLastModification()); - assertNull("expected modification user to be empty", persisted.getLastModifiedBy()); + assertNotNull("expected creation date audit trail", actual.getCreationDate()); + assertEquals("expected creation user audit trail", "auditor", actual.getCreator()); - assertNotNull("expected version to be non null", persisted.getVersion()); - assertTrue("expected version to be greater than 0", persisted.getVersion() > 0L); + assertTrue("creation date is too early", actual.getCreationDate().after(start)); + assertTrue("creation date is too late", actual.getCreationDate().before(new Date())); + + assertNull("expected modification date to be empty", actual.getLastModification()); + assertNull("expected modification user to be empty", actual.getLastModifiedBy()); + + assertNotNull("expected version to be non null", actual.getVersion()); + assertTrue("expected version to be greater than 0", actual.getVersion() > 0L); + }); } @Test @@ -68,11 +72,11 @@ public class AuditingTests { auditorAware.setAuditor(expectedCreator); repository.save(item); - AuditedItem created = repository.findOne(KEY); + AuditedItem created = repository.findOne(KEY).orElse(null); auditorAware.setAuditor(expectedUpdater); repository.save(item); - AuditedItem updated = repository.findOne(KEY); + AuditedItem updated = repository.findOne(KEY).orElse(null); assertNotNull("expected entity to be persisted", updated); assertNotNull("expected creation date audit trail", updated.getCreationDate()); diff --git a/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java index b172e142..e222810f 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2017 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. @@ -20,6 +20,7 @@ import static org.junit.Assert.*; import java.util.Collections; import java.util.List; +import java.util.Optional; import com.couchbase.client.java.Bucket; import com.couchbase.client.java.view.DefaultView; @@ -89,10 +90,12 @@ public class CdiRepositoryTests { assertTrue(repository.exists(bean.getId())); - Person retrieved = repository.findOne(bean.getId()); - assertNotNull(retrieved); - assertEquals(bean.getName(), retrieved.getName()); - assertEquals(bean.getId(), retrieved.getId()); + Optional retrieved = repository.findOne(bean.getId()); + assertTrue(retrieved.isPresent()); + retrieved.ifPresent(actual -> { + assertEquals(bean.getName(), actual.getName()); + assertEquals(bean.getId(), actual.getId()); + }); } /** @@ -109,10 +112,12 @@ public class CdiRepositoryTests { assertTrue(qualifiedPersonRepository.exists(bean.getId())); - Person retrieved = qualifiedPersonRepository.findOne(bean.getId()); - assertNotNull(retrieved); - assertEquals(bean.getName(), retrieved.getName()); - assertEquals(bean.getId(), retrieved.getId()); + Optional retrieved = qualifiedPersonRepository.findOne(bean.getId()); + assertTrue(retrieved.isPresent()); + retrieved.ifPresent(actual -> { + assertEquals(bean.getName(), actual.getName()); + assertEquals(bean.getId(), actual.getId()); + }); } /** diff --git a/src/integration/java/org/springframework/data/couchbase/repository/extending/method/MyRepositoryImpl.java b/src/integration/java/org/springframework/data/couchbase/repository/extending/method/MyRepositoryImpl.java index acd158c6..50a32ecf 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/extending/method/MyRepositoryImpl.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/extending/method/MyRepositoryImpl.java @@ -29,7 +29,7 @@ public class MyRepositoryImpl implements MyRepositoryCustom { CouchbasePersistentEntity itemPersistenceEntity = (CouchbasePersistentEntity) template.getConverter() .getMappingContext() - .getPersistentEntity(MyItem.class); + .getRequiredPersistentEntity(MyItem.class); CouchbaseEntityInformation itemEntityInformation = new MappingCouchbaseEntityInformation(itemPersistenceEntity); diff --git a/src/integration/java/org/springframework/data/couchbase/repository/wiring/RepositoryTemplateWiringTests.java b/src/integration/java/org/springframework/data/couchbase/repository/wiring/RepositoryTemplateWiringTests.java index 7e305854..4ba8dc21 100644 --- a/src/integration/java/org/springframework/data/couchbase/repository/wiring/RepositoryTemplateWiringTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/wiring/RepositoryTemplateWiringTests.java @@ -5,6 +5,7 @@ import static org.mockito.Mockito.*; import java.util.Arrays; import java.util.List; +import java.util.Optional; import com.couchbase.client.java.cluster.ClusterInfo; import com.couchbase.client.java.util.features.CouchbaseFeature; @@ -33,6 +34,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * underlying {@link CouchbaseOperations} beans. * * @author Simon Baslé + * @author Mark Paluch */ @SuppressWarnings("SpringJavaAutowiringInspection") @RunWith(SpringJUnit4ClassRunner.class) @@ -128,13 +130,15 @@ public class RepositoryTemplateWiringTests { boolean existA = repositoryA.exists("testA"); boolean existB = repositoryB.exists("testB"); - Misc valueC = repositoryC.findOne("toto"); + Optional valueC = repositoryC.findOne("toto"); assertTrue(existA); assertFalse(existB); - assertNotNull(valueC); - assertEquals("mock", valueC.id); - assertEquals(true, valueC.random); + assertTrue(valueC.isPresent()); + valueC.ifPresent(actual -> { + assertEquals("mock", actual.id); + assertEquals(true, actual.random); + }); verify(mockOpsA).exists("testA"); verify(mockOpsB).exists("testB"); diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java index ec2b5578..1a657c20 100644 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors + * Copyright 2012-2017 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. @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -86,6 +87,7 @@ import static org.springframework.data.couchbase.core.support.TemplateUtils.SELE * @author Oliver Gierke * @author Simon Baslé * @author Young-Gu Chae + * @author Mark Paluch */ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventPublisherAware { @@ -290,7 +292,7 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP @Override public T findById(final String id, Class entityClass) { - final CouchbasePersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + final CouchbasePersistentEntity entity = mappingContext.getRequiredPersistentEntity(entityClass); RawJsonDocument result = execute(new BucketCallback() { @Override public RawJsonDocument doInBucket() { @@ -573,9 +575,9 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP ensureNotIterable(objectToPersist); final ConvertingPropertyAccessor accessor = getPropertyAccessor(objectToPersist); - final CouchbasePersistentEntity persistentEntity = mappingContext.getPersistentEntity(objectToPersist.getClass()); - final CouchbasePersistentProperty versionProperty = persistentEntity.getVersionProperty(); - final Long version = versionProperty != null ? accessor.getProperty(versionProperty, Long.class) : null; + final CouchbasePersistentEntity persistentEntity = mappingContext.getRequiredPersistentEntity(objectToPersist.getClass()); + final Optional versionProperty = persistentEntity.getVersionProperty(); + final Long version = versionProperty.flatMap(p -> accessor.getProperty(p, Long.class)).orElse(null); maybeEmitEvent(new BeforeConvertEvent(objectToPersist)); final CouchbaseDocument converted = new CouchbaseDocument(); @@ -588,7 +590,7 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP Document doc = encodeAndWrap(converted, version); Document storedDoc; //We will check version only if required - boolean versionPresent = versionProperty != null; + boolean versionPresent = versionProperty.isPresent(); //If version is not set - assumption that document is new, otherwise updating boolean existingDocument = version != null && version > 0L; try { @@ -614,9 +616,9 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP break; } - if (persistentEntity.hasVersionProperty() && storedDoc != null && storedDoc.cas() != 0) { + if (storedDoc != null && storedDoc.cas() != 0) { //inject new cas into the bean - accessor.setProperty(versionProperty, storedDoc.cas()); + versionProperty.ifPresent(p -> accessor.setProperty(p, Optional.ofNullable(storedDoc.cas()))); return true; } return false; @@ -685,16 +687,14 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP Object readEntity = converter.read(entityClass, (CouchbaseDocument) decodeAndUnwrap(data, converted)); final ConvertingPropertyAccessor accessor = getPropertyAccessor(readEntity); - CouchbasePersistentEntity persistentEntity = mappingContext.getPersistentEntity(readEntity.getClass()); - if (persistentEntity.hasVersionProperty()) { - accessor.setProperty(persistentEntity.getVersionProperty(), data.cas()); - } + CouchbasePersistentEntity persistentEntity = mappingContext.getRequiredPersistentEntity(readEntity.getClass()); + persistentEntity.getVersionProperty().ifPresent(p -> accessor.setProperty(p, Optional.ofNullable(data.cas()))); return (T) readEntity; } private final ConvertingPropertyAccessor getPropertyAccessor(Object source) { - CouchbasePersistentEntity entity = mappingContext.getPersistentEntity(source.getClass()); + CouchbasePersistentEntity entity = mappingContext.getRequiredPersistentEntity(source.getClass()); PersistentPropertyAccessor accessor = entity.getPropertyAccessor(source); return new ConvertingPropertyAccessor(accessor, converter.getConversionService()); diff --git a/src/main/java/org/springframework/data/couchbase/core/RxJavaCouchbaseTemplate.java b/src/main/java/org/springframework/data/couchbase/core/RxJavaCouchbaseTemplate.java index 264eec33..ab84b0c7 100644 --- a/src/main/java/org/springframework/data/couchbase/core/RxJavaCouchbaseTemplate.java +++ b/src/main/java/org/springframework/data/couchbase/core/RxJavaCouchbaseTemplate.java @@ -19,6 +19,7 @@ package org.springframework.data.couchbase.core; import static org.springframework.data.couchbase.core.CouchbaseTemplate.ensureNotIterable; import java.util.Collection; +import java.util.Optional; import com.couchbase.client.java.AsyncBucket; import com.couchbase.client.java.Bucket; @@ -47,6 +48,7 @@ import rx.Observable; /** * RxJavaCouchbaseTemplate implements operations using rxjava1 observables * @author Subhashni Balakrishnan + * @author Mark Paluch * @since 3.0 */ public class RxJavaCouchbaseTemplate implements RxJavaCouchbaseOperations { @@ -149,7 +151,7 @@ public class RxJavaCouchbaseTemplate implements RxJavaCouchbaseOperations { } private final ConvertingPropertyAccessor getPropertyAccessor(Object source) { - CouchbasePersistentEntity entity = mappingContext.getPersistentEntity(source.getClass()); + CouchbasePersistentEntity entity = mappingContext.getRequiredPersistentEntity(source.getClass()); PersistentPropertyAccessor accessor = entity.getPropertyAccessor(source); return new ConvertingPropertyAccessor(accessor, converter.getConversionService()); @@ -160,9 +162,9 @@ public class RxJavaCouchbaseTemplate implements RxJavaCouchbaseOperations { ensureNotIterable(objectToPersist); final ConvertingPropertyAccessor accessor = getPropertyAccessor(objectToPersist); - final CouchbasePersistentEntity persistentEntity = mappingContext.getPersistentEntity(objectToPersist.getClass()); - final CouchbasePersistentProperty versionProperty = persistentEntity.getVersionProperty(); - final Long version = versionProperty != null ? accessor.getProperty(versionProperty, Long.class) : null; + final CouchbasePersistentEntity persistentEntity = mappingContext.getRequiredPersistentEntity(objectToPersist.getClass()); + Optional versionProperty = persistentEntity.getVersionProperty(); + final Long version = versionProperty.flatMap(p -> accessor.getProperty(p, Long.class)).orElse(null); final CouchbaseDocument converted = new CouchbaseDocument(); converter.write(objectToPersist, converted); @@ -180,9 +182,9 @@ public class RxJavaCouchbaseTemplate implements RxJavaCouchbaseOperations { .doOnError(e -> TemplateUtils.translateError(e)); } else { final ConvertingPropertyAccessor accessor = getPropertyAccessor(objectToRemove); - final CouchbasePersistentEntity persistentEntity = mappingContext.getPersistentEntity(objectToRemove.getClass()); - final CouchbasePersistentProperty versionProperty = persistentEntity.getVersionProperty(); - final Long version = versionProperty != null ? accessor.getProperty(versionProperty, Long.class) : null; + final CouchbasePersistentEntity persistentEntity = mappingContext.getRequiredPersistentEntity(objectToRemove.getClass()); + final Optional versionProperty = persistentEntity.getVersionProperty(); + final Long version = versionProperty.flatMap(p -> accessor.getProperty(p, Long.class)).orElse(null); final CouchbaseDocument converted = new CouchbaseDocument(); converter.write(objectToRemove, converted); @@ -220,7 +222,7 @@ public class RxJavaCouchbaseTemplate implements RxJavaCouchbaseOperations { @Override public Observable findById(String id, Class entityClass) { - final CouchbasePersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + final CouchbasePersistentEntity entity = mappingContext.getRequiredPersistentEntity(entityClass); if (entity.isTouchOnRead()) { return client.getAndTouch(id, entity.getExpiry(), RawJsonDocument.class) .switchIfEmpty(Observable.just(null)) @@ -336,10 +338,8 @@ public class RxJavaCouchbaseTemplate implements RxJavaCouchbaseOperations { Object readEntity = converter.read(entityClass, (CouchbaseDocument) decodeAndUnwrap(data, converted)); final ConvertingPropertyAccessor accessor = getPropertyAccessor(readEntity); - CouchbasePersistentEntity persistentEntity = mappingContext.getPersistentEntity(readEntity.getClass()); - if (persistentEntity.hasVersionProperty()) { - accessor.setProperty(persistentEntity.getVersionProperty(), data.cas()); - } + CouchbasePersistentEntity persistentEntity = mappingContext.getRequiredPersistentEntity(readEntity.getClass()); + persistentEntity.getVersionProperty().ifPresent(p -> accessor.setProperty(p, Optional.ofNullable(data.cas()))); return (T) readEntity; } diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/DefaultCouchbaseTypeMapper.java b/src/main/java/org/springframework/data/couchbase/core/convert/DefaultCouchbaseTypeMapper.java index 68fc6d05..3921f48b 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/DefaultCouchbaseTypeMapper.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/DefaultCouchbaseTypeMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors + * Copyright 2012-2017 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. @@ -19,11 +19,15 @@ package org.springframework.data.couchbase.core.convert; import org.springframework.data.convert.DefaultTypeMapper; import org.springframework.data.convert.TypeAliasAccessor; import org.springframework.data.couchbase.core.mapping.CouchbaseDocument; +import org.springframework.data.mapping.Alias; + +import java.util.Optional; /** * The Couchbase Type Mapper. * * @author Michael Nitschinger + * @author Mark Paluch */ public class DefaultCouchbaseTypeMapper extends DefaultTypeMapper implements CouchbaseTypeMapper { @@ -58,8 +62,8 @@ public class DefaultCouchbaseTypeMapper extends DefaultTypeMapper entity = (CouchbasePersistentEntity) mappingContext.getPersistentEntity(typeToUse); - if (entity == null) { - throw new MappingException("No mapping metadata found for " + rawType.getName()); - } + CouchbasePersistentEntity entity = (CouchbasePersistentEntity) mappingContext.getRequiredPersistentEntity(typeToUse); return read(entity, source, parent); } @@ -226,30 +224,27 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter final R instance = instantiator.createInstance(entity, provider); final ConvertingPropertyAccessor accessor = getPropertyAccessor(instance); - entity.doWithProperties(new PropertyHandler() { - @Override - public void doWithPersistentProperty(final CouchbasePersistentProperty prop) { - if (!doesPropertyExistInSource(prop) || entity.isConstructorArgument(prop)) { - return; - } - Object obj = prop.isIdProperty() ? source.getId() : getValueInternal(prop, source, instance); - accessor.setProperty(prop, obj); + entity.getPersistentProperties().filter(prop -> { + + if (!(prop.isIdProperty() || source.containsKey(prop.getFieldName())) || entity.isConstructorArgument(prop)) { + return false; } - private boolean doesPropertyExistInSource(final CouchbasePersistentProperty property) { - return property.isIdProperty() || source.containsKey(property.getFieldName()); - } + return true; + }).forEach(prop -> { + + Optional obj = prop.isIdProperty() ? Optional.ofNullable(source.getId()) : getValueInternal(prop, source, instance); + accessor.setProperty(prop, obj); }); - entity.doWithAssociations(new AssociationHandler() { - @Override - public void doWithAssociation(final Association association) { - CouchbasePersistentProperty inverseProp = association.getInverse(); - Object obj = getValueInternal(inverseProp, source, instance); - accessor.setProperty(inverseProp, obj); - } + entity.getAssociations().forEach(association -> { + CouchbasePersistentProperty inverseProp = association.getInverse(); + Optional obj = getValueInternal(inverseProp, source, instance); + accessor.setProperty(inverseProp, obj); + }); + return instance; } @@ -261,7 +256,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter * @param parent the optional parent. * @return the actual property value. */ - protected Object getValueInternal(final CouchbasePersistentProperty property, final CouchbaseDocument source, + protected Optional getValueInternal(final CouchbasePersistentProperty property, final CouchbaseDocument source, final Object parent) { return new CouchbasePropertyValueProvider(source, spELContext, parent).getPropertyValue(property); } @@ -280,7 +275,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter final DefaultSpELExpressionEvaluator evaluator, final Object parent) { CouchbasePropertyValueProvider provider = new CouchbasePropertyValueProvider(source, evaluator, parent); PersistentEntityParameterValueProvider parameterProvider = - new PersistentEntityParameterValueProvider(entity, provider, parent); + new PersistentEntityParameterValueProvider(entity, provider, Optional.ofNullable(parent)); return new ConverterAwareSpELExpressionParameterValueProvider(evaluator, conversionService, parameterProvider, parent); @@ -304,16 +299,13 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter Map sourceMap = source.getPayload(); for (Map.Entry entry : sourceMap.entrySet()) { - Object key = entry.getKey(); Object value = entry.getValue(); - TypeInformation keyTypeInformation = type.getComponentType(); - if (keyTypeInformation != null) { - Class keyType = keyTypeInformation.getType(); - key = conversionService.convert(key, keyType); - } + Object key = type.getComponentType().map(TypeInformation::getType) // + .map(keyType -> (Object) conversionService.convert(entry.getKey(), keyType)) // + .orElse(entry.getKey()); - TypeInformation valueType = type.getMapValueType(); + TypeInformation valueType = type.getMapValueType().orElse(null); if (value instanceof CouchbaseDocument) { map.put(key, read(valueType, (CouchbaseDocument) value, parent)); } else if (value instanceof CouchbaseList) { @@ -406,7 +398,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter throw new IllegalArgumentException("Root Document must be either CouchbaseDocument or Map."); } - CouchbasePersistentEntity entity = mappingContext.getPersistentEntity(source.getClass()); + CouchbasePersistentEntity entity = mappingContext.getPersistentEntity(source.getClass()).orElse(null); writeInternal(source, target, entity); addCustomTypeKeyIfNecessary(typeHint, source, target); } @@ -443,45 +435,49 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter } final ConvertingPropertyAccessor accessor = getPropertyAccessor(source); - final CouchbasePersistentProperty idProperty = entity.getIdProperty(); - final CouchbasePersistentProperty versionProperty = entity.getVersionProperty(); + final Optional idProperty = entity.getIdProperty(); + final Optional versionProperty = entity.getVersionProperty(); - if (idProperty != null && target.getId() == null) { - String id = accessor.getProperty(idProperty, String.class); - target.setId(id); + if (target.getId() == null) { + idProperty.ifPresent(id -> { + target.setId(accessor.getProperty(id, String.class).orElse(null)); + }); } target.setExpiration(entity.getExpiry()); - entity.doWithProperties(new PropertyHandler() { - @Override - public void doWithPersistentProperty(final CouchbasePersistentProperty prop) { - if (prop.equals(idProperty) || (versionProperty != null && prop.equals(versionProperty))) { - return; - } else if(enableStrictFieldChecking && !prop.isAnnotationPresent(Field.class)){ - return; - } + entity.getPersistentProperties().filter(prop -> { - Object propertyObj = accessor.getProperty(prop, prop.getType()); - if (null != propertyObj) { - if (!conversions.isSimpleType(propertyObj.getClass())) { - writePropertyInternal(propertyObj, target, prop); - } else { - writeSimpleInternal(propertyObj, target, prop.getFieldName()); - } - } + if (idProperty.filter(prop::equals).isPresent()) { + return false; } + + if (versionProperty.filter(prop::equals).isPresent()) { + return false; + } + + if (enableStrictFieldChecking && !prop.isAnnotationPresent(Field.class)) { + return false; + } + return true; + }).forEach(prop -> { + Optional propertyObj = accessor.getProperty(prop, (Class) prop.getType()); + propertyObj.ifPresent(o -> { + if (!conversions.isSimpleType(o.getClass())) { + writePropertyInternal(o, target, prop); + } else { + writeSimpleInternal(o, target, prop.getFieldName()); + } + }); }); - entity.doWithAssociations(new AssociationHandler() { - @Override - public void doWithAssociation(final Association association) { - CouchbasePersistentProperty inverseProp = association.getInverse(); - Class type = inverseProp.getType(); - Object propertyObj = accessor.getProperty(inverseProp, type); - if (null != propertyObj) { - writePropertyInternal(propertyObj, target, inverseProp); - } - } + + entity.getAssociations().forEach(association -> { + CouchbasePersistentProperty inverseProp = association.getInverse(); + Class type = inverseProp.getType(); + Optional propertyObj = accessor.getProperty(inverseProp, (Class) type); + propertyObj.ifPresent(o -> { + writePropertyInternal(o, target, inverseProp); + }); }); } @@ -526,7 +522,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter addCustomTypeKeyIfNecessary(type, source, propertyDoc); CouchbasePersistentEntity entity = isSubtype(prop.getType(), source.getClass()) ? mappingContext - .getPersistentEntity(source.getClass()) : mappingContext.getPersistentEntity(type); + .getRequiredPersistentEntity(source.getClass()) : mappingContext.getRequiredPersistentEntity(type); writeInternal(source, propertyDoc, entity); target.put(name, propertyDoc); } @@ -568,7 +564,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter target.put(simpleKey, writeCollectionInternal(asCollection(val), new CouchbaseList(conversions.getSimpleTypeHolder()), type.getMapValueType())); } else { CouchbaseDocument embeddedDoc = new CouchbaseDocument(); - TypeInformation valueTypeInfo = type.isMap() ? type.getMapValueType() : ClassTypeInformation.OBJECT; + TypeInformation valueTypeInfo = type.isMap() ? type.getMapValueType().orElse(ClassTypeInformation.OBJECT) : ClassTypeInformation.OBJECT; writeInternal(val, embeddedDoc, valueTypeInfo); target.put(simpleKey, embeddedDoc); } @@ -588,7 +584,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter * @return the created couchbase list. */ private CouchbaseList createCollection(final Collection collection, final CouchbasePersistentProperty prop) { - return writeCollectionInternal(collection, new CouchbaseList(conversions.getSimpleTypeHolder()), prop.getTypeInformation()); + return writeCollectionInternal(collection, new CouchbaseList(conversions.getSimpleTypeHolder()), Optional.of(prop.getTypeInformation())); } /** @@ -600,8 +596,9 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter * @return the created couchbase list. */ private CouchbaseList writeCollectionInternal(final Collection source, final CouchbaseList target, - final TypeInformation type) { - TypeInformation componentType = type == null ? null : type.getComponentType(); + final Optional> type) { + + Optional> componentType = type.flatMap(TypeInformation::getComponentType); for (Object element : source) { Class elementType = element == null ? null : element.getClass(); @@ -611,8 +608,10 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter } else if (element instanceof Collection || elementType.isArray()) { target.put(writeCollectionInternal(asCollection(element), new CouchbaseList(conversions.getSimpleTypeHolder()), componentType)); } else { + + TypeInformation typeInformation = componentType.orElse(null); CouchbaseDocument embeddedDoc = new CouchbaseDocument(); - writeInternal(element, embeddedDoc, componentType); + writeInternal(element, embeddedDoc, typeInformation); target.put(embeddedDoc); } @@ -641,7 +640,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class; Collection items = targetType.getType().isArray() ? new ArrayList() : CollectionFactory .createCollection(collectionType, source.size(false)); - TypeInformation componentType = targetType.getComponentType(); + TypeInformation componentType = targetType.getComponentType().orElse(null); Class rawComponentType = componentType == null ? null : componentType.getType(); for (int i = 0; i < source.size(false); i++) { @@ -756,7 +755,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter } private ConvertingPropertyAccessor getPropertyAccessor(Object source) { - CouchbasePersistentEntity entity = mappingContext.getPersistentEntity(source.getClass()); + CouchbasePersistentEntity entity = mappingContext.getRequiredPersistentEntity(source.getClass()); PersistentPropertyAccessor accessor = entity.getPropertyAccessor(source); return new ConvertingPropertyAccessor(accessor, conversionService); @@ -799,18 +798,18 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter @Override @SuppressWarnings("unchecked") - public R getPropertyValue(final CouchbasePersistentProperty property) { - String expression = property.getSpelExpression(); - Object value = expression != null ? evaluator.evaluate(expression) : source.get(property.getFieldName()); + public Optional getPropertyValue(final CouchbasePersistentProperty property) { + + Object value = property.getSpelExpression().map(evaluator::evaluate).orElseGet(() -> source.get(property.getFieldName())); if (property.isIdProperty()) { - return (R) source.getId(); + return Optional.ofNullable((R) source.getId()); } if (value == null) { - return null; + return Optional.empty(); } - return readValue(value, property.getTypeInformation(), parent); + return Optional.ofNullable(readValue(value, property.getTypeInformation(), parent)); } } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java b/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java index 18347275..4902eb92 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors + * Copyright 2012-2017 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. @@ -32,9 +32,10 @@ import java.util.concurrent.TimeUnit; * The representation of a persistent entity. * * @author Michael Nitschinger + * @author Mark Paluch */ public class BasicCouchbasePersistentEntity extends BasicPersistentEntity - implements CouchbasePersistentEntity, EnvironmentAware { + implements CouchbasePersistentEntity, EnvironmentAware { private Environment environment; @@ -74,8 +75,12 @@ public class BasicCouchbasePersistentEntity extends BasicPersistentEntity couchbasePersistentProperty.isAnnotationPresent(Id.class)) + .orElse(false); + boolean currentSpringId = this.getIdProperty() + .map(couchbasePersistentProperty -> couchbasePersistentProperty.isAnnotationPresent(org.springframework.data.annotation.Id.class)) + .orElse(false); boolean candidateCbId = property.isAnnotationPresent(Id.class); boolean candidateSpringId = property.isAnnotationPresent(org.springframework.data.annotation.Id.class); @@ -137,7 +142,7 @@ public class BasicCouchbasePersistentEntity extends BasicPersistentEntity 0; } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentProperty.java b/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentProperty.java index a30613e6..25f06aa5 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentProperty.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentProperty.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors + * Copyright 2012-2017 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. @@ -16,19 +16,19 @@ package org.springframework.data.couchbase.core.mapping; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Field; - +import com.couchbase.client.java.repository.annotation.Field; import com.couchbase.client.java.repository.annotation.Id; - import org.springframework.data.mapping.Association; import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; import org.springframework.data.mapping.model.FieldNamingStrategy; import org.springframework.data.mapping.model.MappingException; +import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.util.StringUtils; +import java.util.Optional; + /** * Implements annotated property representations of a given {@link com.couchbase.client.java.repository.annotation.Field} instance. *

@@ -36,27 +36,27 @@ import org.springframework.util.StringUtils; * supports overriding of the actual property name by providing custom annotations.

* * @author Michael Nitschinger + * @author Mark Paluch */ public class BasicCouchbasePersistentProperty - extends AnnotationBasedPersistentProperty - implements CouchbasePersistentProperty { + extends AnnotationBasedPersistentProperty + implements CouchbasePersistentProperty { private final FieldNamingStrategy fieldNamingStrategy; /** * Create a new instance of the BasicCouchbasePersistentProperty class. * - * @param field the field of the original reflection. - * @param propertyDescriptor the PropertyDescriptor. - * @param owner the original owner of the property. + * @param property the PropertyDescriptor. + * @param owner the original owner of the property. * @param simpleTypeHolder the type holder. */ - public BasicCouchbasePersistentProperty(final Field field, final PropertyDescriptor propertyDescriptor, + public BasicCouchbasePersistentProperty(Property property, final CouchbasePersistentEntity owner, final SimpleTypeHolder simpleTypeHolder, final FieldNamingStrategy fieldNamingStrategy) { - super(field, propertyDescriptor, owner, simpleTypeHolder); + super(property, owner, simpleTypeHolder); this.fieldNamingStrategy = fieldNamingStrategy == null ? PropertyNameFieldNamingStrategy.INSTANCE - : fieldNamingStrategy; + : fieldNamingStrategy; } /** @@ -75,21 +75,20 @@ public class BasicCouchbasePersistentProperty */ @Override public String getFieldName() { - com.couchbase.client.java.repository.annotation.Field annotation = getField(). - getAnnotation(com.couchbase.client.java.repository.annotation.Field.class); + Optional annotation = findAnnotation(com.couchbase.client.java.repository.annotation.Field.class); - if (annotation != null && StringUtils.hasText(annotation.value())) { - return annotation.value(); - } + return annotation.map(Field::value).filter(StringUtils::hasText).orElseGet(() -> { - String fieldName = fieldNamingStrategy.getFieldName(this); + String fieldName = fieldNamingStrategy.getFieldName(this); - if (!StringUtils.hasText(fieldName)) { - throw new MappingException(String.format("Invalid (null or empty) field name returned for property %s by %s!", - this, fieldNamingStrategy.getClass())); - } + if (!StringUtils.hasText(fieldName)) { + throw new MappingException(String.format("Invalid (null or empty) field name returned for property %s by %s!", + this, fieldNamingStrategy.getClass())); + } + + return fieldName; + }); - return fieldName; } // DATACOUCH-145: allows SDK's @Id annotation to be used diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java index e75bf14d..4b2526e7 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors + * Copyright 2012-2017 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. @@ -16,14 +16,12 @@ package org.springframework.data.couchbase.core.mapping; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Field; - import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.data.mapping.context.AbstractMappingContext; import org.springframework.data.mapping.model.FieldNamingStrategy; +import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.TypeInformation; @@ -83,16 +81,15 @@ public class CouchbaseMappingContext /** * Creates a concrete property based on the field information and entity. * - * @param field the reflection on the field to be used as a property. - * @param descriptor the property descriptor. + * @param property the property descriptor. * @param owner the entity which owns the property. * @param simpleTypeHolder the type holder. * @return the constructed property. */ @Override - protected CouchbasePersistentProperty createPersistentProperty(final Field field, final PropertyDescriptor descriptor, + protected CouchbasePersistentProperty createPersistentProperty(Property property, final BasicCouchbasePersistentEntity owner, final SimpleTypeHolder simpleTypeHolder) { - return new BasicCouchbasePersistentProperty(field, descriptor, owner, simpleTypeHolder, fieldNamingStrategy); + return new BasicCouchbasePersistentProperty(property, owner, simpleTypeHolder, fieldNamingStrategy); } /** diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/AuditingEventListener.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/AuditingEventListener.java index abe5cf0e..0957cc60 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/AuditingEventListener.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/AuditingEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors + * Copyright 2012-2017 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. @@ -23,11 +23,14 @@ import org.springframework.data.auditing.IsNewAwareAuditingHandler; import org.springframework.data.mapping.context.MappingContext; import org.springframework.util.Assert; +import java.util.Optional; + /** * Event listener to populate auditing related fields on an entity about to be saved. * * @author Oliver Gierke * @author Simon Baslé + * @author Mark Paluch */ public class AuditingEventListener implements ApplicationListener> { @@ -51,6 +54,6 @@ public class AuditingEventListener implements ApplicationListener event) { Object entity = event.getSource(); - auditingHandlerFactory.getObject().markAudited(entity); + auditingHandlerFactory.getObject().markAudited(Optional.of(entity)); } } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/couchbase/repository/cdi/CouchbaseRepositoryBean.java b/src/main/java/org/springframework/data/couchbase/repository/cdi/CouchbaseRepositoryBean.java index 4865824a..8d27d59d 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/cdi/CouchbaseRepositoryBean.java +++ b/src/main/java/org/springframework/data/couchbase/repository/cdi/CouchbaseRepositoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2017 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. @@ -20,6 +20,7 @@ import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import java.lang.annotation.Annotation; +import java.util.Optional; import java.util.Set; import org.springframework.data.couchbase.core.CouchbaseOperations; @@ -50,7 +51,7 @@ public class CouchbaseRepositoryBean extends CdiRepositoryBean { */ public CouchbaseRepositoryBean(Bean operations, Set qualifiers, Class repositoryType, BeanManager beanManager, CustomRepositoryImplementationDetector detector) { - super(qualifiers, repositoryType, beanManager, detector); + super(qualifiers, repositoryType, beanManager, Optional.of(detector)); Assert.notNull(operations, "Cannot create repository with 'null' for CouchbaseOperations."); this.couchbaseOperationsBean = operations; @@ -61,11 +62,17 @@ public class CouchbaseRepositoryBean extends CdiRepositoryBean { * @see org.springframework.data.repository.cdi.CdiRepositoryBean#create(javax.enterprise.context.spi.CreationalContext, java.lang.Class, java.lang.Object) */ @Override - protected T create(CreationalContext creationalContext, Class repositoryType, Object customImplementation) { + protected T create(CreationalContext creationalContext, Class repositoryType, Optional customImplementation) { + CouchbaseOperations couchbaseOperations = getDependencyInstance(couchbaseOperationsBean, CouchbaseOperations.class); RepositoryOperationsMapping couchbaseOperationsMapping = new RepositoryOperationsMapping(couchbaseOperations); IndexManager indexManager = new IndexManager(); - return new CouchbaseRepositoryFactory(couchbaseOperationsMapping, indexManager).getRepository(repositoryType, customImplementation); + + CouchbaseRepositoryFactory factory = + new CouchbaseRepositoryFactory(couchbaseOperationsMapping, indexManager); + + return customImplementation.map(o -> factory.getRepository(repositoryType, o)) + .orElseGet(() -> factory.getRepository(repositoryType)); } @Override diff --git a/src/main/java/org/springframework/data/couchbase/repository/cdi/ReactiveCouchbaseRepositoryBean.java b/src/main/java/org/springframework/data/couchbase/repository/cdi/ReactiveCouchbaseRepositoryBean.java index ab1981a6..c9c64676 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/cdi/ReactiveCouchbaseRepositoryBean.java +++ b/src/main/java/org/springframework/data/couchbase/repository/cdi/ReactiveCouchbaseRepositoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2017 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. @@ -20,6 +20,7 @@ import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import java.lang.annotation.Annotation; +import java.util.Optional; import java.util.Set; import org.springframework.data.couchbase.core.RxJavaCouchbaseOperations; @@ -33,6 +34,7 @@ import org.springframework.util.Assert; /** * A bean which represents a Couchbase repository. * @author Subhashni Balakrishnan + * @author Mark Paluch */ public class ReactiveCouchbaseRepositoryBean extends CdiRepositoryBean { @@ -50,22 +52,27 @@ public class ReactiveCouchbaseRepositoryBean extends CdiRepositoryBean { */ public ReactiveCouchbaseRepositoryBean(Bean reactiveOperations, Set qualifiers, Class repositoryType, BeanManager beanManager, CustomRepositoryImplementationDetector detector) { - super(qualifiers, repositoryType, beanManager, detector); + super(qualifiers, repositoryType, beanManager, Optional.of(detector)); Assert.notNull(reactiveOperations, "Cannot create repository with 'null' for ReactiveCouchbaseOperations."); this.reactiveCouchbaseOperationsBean = reactiveOperations; } + /* * (non-Javadoc) * @see org.springframework.data.repository.cdi.CdiRepositoryBean#create(javax.enterprise.context.spi.CreationalContext, java.lang.Class, java.lang.Object) */ @Override - protected T create(CreationalContext creationalContext, Class repositoryType, Object customImplementation) { + protected T create(CreationalContext creationalContext, Class repositoryType, Optional customImplementation) { RxJavaCouchbaseOperations reactiveCouchbaseOperations = getDependencyInstance(reactiveCouchbaseOperationsBean, RxJavaCouchbaseOperations.class); ReactiveRepositoryOperationsMapping reactiveCouchbaseOperationsMapping = new ReactiveRepositoryOperationsMapping(reactiveCouchbaseOperations); IndexManager indexManager = new IndexManager(); - return new ReactiveCouchbaseRepositoryFactory(reactiveCouchbaseOperationsMapping, indexManager).getRepository(repositoryType, customImplementation); + + ReactiveCouchbaseRepositoryFactory factory = new ReactiveCouchbaseRepositoryFactory(reactiveCouchbaseOperationsMapping, indexManager); + + return customImplementation.map(o -> factory.getRepository(repositoryType, o)) + .orElseGet(() -> factory.getRepository(repositoryType)); } @Override diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/AbstractN1qlBasedQuery.java b/src/main/java/org/springframework/data/couchbase/repository/query/AbstractN1qlBasedQuery.java index b8b47fd8..e7e560b0 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/AbstractN1qlBasedQuery.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/AbstractN1qlBasedQuery.java @@ -19,6 +19,7 @@ package org.springframework.data.couchbase.repository.query; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import com.couchbase.client.java.document.json.JsonArray; import com.couchbase.client.java.document.json.JsonObject; @@ -85,7 +86,7 @@ public abstract class AbstractN1qlBasedQuery implements RepositoryQuery { public Object execute(Object[] parameters) { ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters); - ResultProcessor processor = this.queryMethod.getResultProcessor().withDynamicProjection(accessor); + ResultProcessor processor = this.queryMethod.getResultProcessor().withDynamicProjection(Optional.of(accessor)); ReturnedType returnedType = processor.getReturnedType(); Class typeToRead = returnedType.getTypeToRead(); diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/N1qlCountQueryCreator.java b/src/main/java/org/springframework/data/couchbase/repository/query/N1qlCountQueryCreator.java index e457252d..c883e345 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/N1qlCountQueryCreator.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/N1qlCountQueryCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors + * Copyright 2012-2017 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. @@ -16,6 +16,7 @@ package org.springframework.data.couchbase.repository.query; import java.util.Iterator; +import java.util.Optional; import org.springframework.data.couchbase.core.convert.CouchbaseConverter; import org.springframework.data.domain.Pageable; @@ -30,7 +31,7 @@ import com.couchbase.client.java.query.dsl.path.WherePath; /** * * @author Mark Ramach - * + * @author Mark Paluch */ public class N1qlCountQueryCreator extends N1qlQueryCreator { @@ -42,7 +43,7 @@ public class N1qlCountQueryCreator extends N1qlQueryCreator { @Override protected LimitPath complete(Expression criteria, Sort sort) { // Sorting is not allowed on aggregate count queries. - return super.complete(criteria, null); + return super.complete(criteria, Sort.unsorted()); } private static class CountParameterAccessor implements ParameterAccessor { @@ -54,14 +55,14 @@ public class N1qlCountQueryCreator extends N1qlQueryCreator { } public Pageable getPageable() { - return delegate.getPageable() != null ? new CountPageable(delegate.getPageable()) : null; + return delegate.getPageable() != Pageable.NONE ? new CountPageable(delegate.getPageable()) : Pageable.NONE; } public Sort getSort() { - return null; + return Sort.unsorted(); } - public Class getDynamicProjection() { + public Optional> getDynamicProjection() { return delegate.getDynamicProjection(); } @@ -95,13 +96,13 @@ public class N1qlCountQueryCreator extends N1qlQueryCreator { return delegate.getPageSize(); } - public int getOffset() { + public long getOffset() { return delegate.getOffset(); } public Sort getSort() { // Sorting is not allowed on aggregate count queries. - return null; + return Sort.unsorted(); } public Pageable next() { diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/N1qlQueryCreator.java b/src/main/java/org/springframework/data/couchbase/repository/query/N1qlQueryCreator.java index d0449ed2..840495a2 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/N1qlQueryCreator.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/N1qlQueryCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors + * Copyright 2012-2017 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. @@ -88,6 +88,7 @@ import org.springframework.data.repository.query.parser.PartTree; *

* * @author Simon Baslé + * @author Mark Paluch */ public class N1qlQueryCreator extends AbstractQueryCreator { @@ -131,14 +132,12 @@ public class N1qlQueryCreator extends AbstractQueryCreator typeToRead = returnedType.getTypeToRead(); diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/SpatialViewQueryCreator.java b/src/main/java/org/springframework/data/couchbase/repository/query/SpatialViewQueryCreator.java index 7dd67bab..63fbd7b8 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/SpatialViewQueryCreator.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/SpatialViewQueryCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors + * Copyright 2012-2017 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. @@ -69,6 +69,8 @@ import org.springframework.data.repository.query.parser.PartTree; * *

* Additionally, {@link PartTree#isLimiting()} will trigger usage of {@link SpatialViewQuery#limit(int) limit}. + * + * @author Mark Paluch */ public class SpatialViewQueryCreator extends AbstractQueryCreator { @@ -240,7 +242,7 @@ public class SpatialViewQueryCreator extends AbstractQueryCreator namedValues.put(name, value)); } } return namedValues; diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/StringN1qlBasedQuery.java b/src/main/java/org/springframework/data/couchbase/repository/query/StringN1qlBasedQuery.java index 64ea995c..1bb92121 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/StringN1qlBasedQuery.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/StringN1qlBasedQuery.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors + * Copyright 2012-2017 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. @@ -53,6 +53,7 @@ import org.springframework.util.Assert; * * @author Simon Baslé * @author Subhashni Balakrishnan + * @author Mark Paluch */ public class StringN1qlBasedQuery extends AbstractN1qlBasedQuery { private final SpelExpressionParser parser; @@ -89,18 +90,20 @@ public class StringN1qlBasedQuery extends AbstractN1qlBasedQuery { String limitByPart = ""; Sort sort = accessor.getSort(); - if (sort != null) { + if (sort.isSorted()) { com.couchbase.client.java.query.dsl.Sort[] cbSorts = N1qlUtils.createSort(sort, getCouchbaseOperations().getConverter()); orderByPart = " " + new DefaultOrderByPath(null).orderBy(cbSorts).toString(); } if (queryMethod.isPageQuery()) { Pageable pageable = accessor.getPageable(); - Assert.notNull(pageable); - limitByPart = " " + new DefaultLimitPath(null).limit(pageable.getPageSize()).offset(pageable.getOffset()).toString(); + Assert.notNull(pageable, "Pageable must not be null!"); + limitByPart = " " + new DefaultLimitPath(null).limit(pageable.getPageSize()) + .offset(Math.toIntExact(pageable.getOffset())).toString(); } else if (queryMethod.isSliceQuery()) { Pageable pageable = accessor.getPageable(); - Assert.notNull(pageable); - limitByPart = " " + new DefaultLimitPath(null).limit(pageable.getPageSize() + 1).offset(pageable.getOffset()).toString(); + Assert.notNull(pageable, "Pageable must not be null!"); + limitByPart = " " + new DefaultLimitPath(null).limit(pageable.getPageSize() + 1) + .offset(Math.toIntExact(pageable.getOffset())).toString(); } return N1qlQuery.simple(parsedStatement + orderByPart + limitByPart).statement(); } diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/ViewQueryCreator.java b/src/main/java/org/springframework/data/couchbase/repository/query/ViewQueryCreator.java index 8c51a227..ffc4d319 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/ViewQueryCreator.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/ViewQueryCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors + * Copyright 2012-2017 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. @@ -275,7 +275,7 @@ public class ViewQueryCreator extends AbstractQueryCreator it = sort.iterator(); while(it.hasNext()) { diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/support/N1qlUtils.java b/src/main/java/org/springframework/data/couchbase/repository/query/support/N1qlUtils.java index 0d0fd4b9..a65fcdd9 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/support/N1qlUtils.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/support/N1qlUtils.java @@ -65,6 +65,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; * * @author Simon Baslé * @author Subhashni Balakrishnan + * @author Mark Paluch */ public class N1qlUtils { @@ -107,10 +108,10 @@ public class N1qlUtils { if (returnedType != null && returnedType.needsCustomConstruction()) { List properties = returnedType.getInputProperties(); - CouchbasePersistentEntity entity = converter.getMappingContext().getPersistentEntity(returnedType.getDomainType()); + CouchbasePersistentEntity entity = converter.getMappingContext().getRequiredPersistentEntity(returnedType.getDomainType()); for (String property : properties) { - expList.add(path(bucket, i(entity.getPersistentProperty(property).getFieldName()))); + expList.add(path(bucket, i(entity.getRequiredPersistentProperty(property).getFieldName()))); } } else { expList.add(path(bucket, "*")); diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseRepositoryFactory.java b/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseRepositoryFactory.java index 3836acb3..fd8315df 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseRepositoryFactory.java +++ b/src/main/java/org/springframework/data/couchbase/repository/support/CouchbaseRepositoryFactory.java @@ -18,6 +18,7 @@ package org.springframework.data.couchbase.repository.support; import java.io.Serializable; import java.lang.reflect.Method; +import java.util.Optional; import com.couchbase.client.java.util.features.CouchbaseFeature; @@ -111,12 +112,8 @@ public class CouchbaseRepositoryFactory extends RepositoryFactorySupport { */ @Override public CouchbaseEntityInformation getEntityInformation(final Class domainClass) { - CouchbasePersistentEntity entity = mappingContext.getPersistentEntity(domainClass); - - if (entity == null) { - throw new MappingException(String.format("Could not lookup mapping metadata for domain class %s!", domainClass.getName())); - } + CouchbasePersistentEntity entity = mappingContext.getRequiredPersistentEntity(domainClass); return new MappingCouchbaseEntityInformation((CouchbasePersistentEntity) entity); } @@ -206,8 +203,8 @@ public class CouchbaseRepositoryFactory extends RepositoryFactorySupport { } @Override - protected QueryLookupStrategy getQueryLookupStrategy(QueryLookupStrategy.Key key, EvaluationContextProvider contextProvider) { - return new CouchbaseQueryLookupStrategy(contextProvider); + protected Optional getQueryLookupStrategy(QueryLookupStrategy.Key key, EvaluationContextProvider contextProvider) { + return Optional.of(new CouchbaseQueryLookupStrategy(contextProvider)); } /** diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/N1qlCouchbaseRepository.java b/src/main/java/org/springframework/data/couchbase/repository/support/N1qlCouchbaseRepository.java index 91b22fbf..0c4696ae 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/support/N1qlCouchbaseRepository.java +++ b/src/main/java/org/springframework/data/couchbase/repository/support/N1qlCouchbaseRepository.java @@ -105,14 +105,14 @@ public class N1qlCouchbaseRepository //apply the sort if available LimitPath limitPath = groupBy; - if (pageable.getSort() != null) { + if (pageable.getSort().isSorted()) { com.couchbase.client.java.query.dsl.Sort[] orderings = N1qlUtils.createSort(pageable.getSort(), getCouchbaseOperations().getConverter()); limitPath = groupBy.orderBy(orderings); } //apply the paging - Statement pageStatement = limitPath.limit(pageable.getPageSize()).offset(pageable.getOffset()); + Statement pageStatement = limitPath.limit(pageable.getPageSize()).offset(Math.toIntExact(pageable.getOffset())); //fire the query N1qlQuery query = N1qlQuery.simple(pageStatement, N1qlParams.build().consistency(consistency)); diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/ReactiveCouchbaseRepositoryFactory.java b/src/main/java/org/springframework/data/couchbase/repository/support/ReactiveCouchbaseRepositoryFactory.java index 909a9402..0a2fb0d5 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/support/ReactiveCouchbaseRepositoryFactory.java +++ b/src/main/java/org/springframework/data/couchbase/repository/support/ReactiveCouchbaseRepositoryFactory.java @@ -17,6 +17,7 @@ package org.springframework.data.couchbase.repository.support; import java.io.Serializable; import java.lang.reflect.Method; +import java.util.Optional; import com.couchbase.client.java.util.features.CouchbaseFeature; import org.springframework.core.annotation.AnnotationUtils; @@ -41,7 +42,8 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.util.Assert; /** - * @Subhashni Balakrishnan + * @author Subhashni Balakrishnan + * @author Mark Paluch * @since 3.0 */ public class ReactiveCouchbaseRepositoryFactory extends ReactiveRepositoryFactorySupport { @@ -96,11 +98,7 @@ public class ReactiveCouchbaseRepositoryFactory extends ReactiveRepositoryFactor */ @Override public CouchbaseEntityInformation getEntityInformation(final Class domainClass) { - CouchbasePersistentEntity entity = mappingContext.getPersistentEntity(domainClass); - - if (entity == null) { - throw new MappingException(String.format("Could not lookup mapping metadata for domain class %s!", domainClass.getName())); - } + CouchbasePersistentEntity entity = mappingContext.getRequiredPersistentEntity(domainClass); return new MappingCouchbaseEntityInformation((CouchbasePersistentEntity) entity); } @@ -192,8 +190,8 @@ public class ReactiveCouchbaseRepositoryFactory extends ReactiveRepositoryFactor } @Override - protected QueryLookupStrategy getQueryLookupStrategy(QueryLookupStrategy.Key key, EvaluationContextProvider contextProvider) { - return new ReactiveCouchbaseRepositoryFactory.CouchbaseQueryLookupStrategy(contextProvider); + protected Optional getQueryLookupStrategy(QueryLookupStrategy.Key key, EvaluationContextProvider contextProvider) { + return Optional.of(new ReactiveCouchbaseRepositoryFactory.CouchbaseQueryLookupStrategy(contextProvider)); } /** diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java b/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java index 154a163c..06d79541 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java +++ b/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java @@ -19,6 +19,7 @@ package org.springframework.data.couchbase.repository.support; import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import com.couchbase.client.java.document.json.JsonArray; import com.couchbase.client.java.error.DocumentDoesNotExistException; @@ -100,9 +101,9 @@ public class SimpleCouchbaseRepository implements Co } @Override - public T findOne(ID id) { + public Optional findOne(ID id) { Assert.notNull(id, "The given id must not be null!"); - return couchbaseOperations.findById(id.toString(), entityInformation.getJavaType()); + return Optional.ofNullable(couchbaseOperations.findById(id.toString(), entityInformation.getJavaType())); } @Override diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java b/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java index 223b437f..ea50669d 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2017 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. @@ -18,15 +18,15 @@ package org.springframework.data.couchbase.core.mapping; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import java.lang.reflect.Field; +import java.util.Optional; import org.junit.Before; import org.junit.Test; import org.springframework.data.annotation.Id; -import org.springframework.data.mapping.model.MappingException; +import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.ClassTypeInformation; @@ -36,6 +36,7 @@ import org.springframework.util.ReflectionUtils; * Verifies the correct behavior of properties on persistable objects. * * @author Michael Nitschinger + * @author Mark Paluch */ public class BasicCouchbasePersistentPropertyTests { @@ -50,7 +51,7 @@ public class BasicCouchbasePersistentPropertyTests { @Before public void setUp() { entity = new BasicCouchbasePersistentEntity( - ClassTypeInformation.from(Beer.class)); + ClassTypeInformation.from(Beer.class)); } /** @@ -74,7 +75,7 @@ public class BasicCouchbasePersistentPropertyTests { @Test public void testPrefersSpringIdAnnotation() { BasicCouchbasePersistentEntity test = new BasicCouchbasePersistentEntity( - ClassTypeInformation.from(Beer.class)); + ClassTypeInformation.from(Beer.class)); Field sdkIdField = ReflectionUtils.findField(Beer.class, "sdkId"); CouchbasePersistentProperty sdkIdProperty = getPropertyFor(sdkIdField); @@ -89,24 +90,32 @@ public class BasicCouchbasePersistentPropertyTests { assertTrue(sdkIdProperty.isIdProperty()); assertTrue(springIdProperty.isIdProperty()); - assertEquals(springIdProperty, test.getIdProperty()); + Optional property = test.getIdProperty(); + assertTrue(property.isPresent()); + property.ifPresent(actual -> { + assertEquals(springIdProperty, actual); + }); } @Test public void testAcceptsSdkIdAnnotation() { BasicCouchbasePersistentEntity test = new BasicCouchbasePersistentEntity( - ClassTypeInformation.from(SdkIdentified.class)); + ClassTypeInformation.from(SdkIdentified.class)); Field id = ReflectionUtils.findField(SdkIdentified.class, "id"); CouchbasePersistentProperty idProperty = getPropertyFor(id); test.addPersistentProperty(idProperty); - assertEquals(idProperty, test.getIdProperty()); + Optional property = test.getIdProperty(); + assertTrue(property.isPresent()); + property.ifPresent(actual -> { + assertEquals(idProperty, actual); + }); } @Test public void testSdkIdAnnotationEvaluatedAfterSpringIdAnnotationIsIgnored() { BasicCouchbasePersistentEntity test = new BasicCouchbasePersistentEntity( - ClassTypeInformation.from(Beer.class)); + ClassTypeInformation.from(Beer.class)); Field sdkIdField = ReflectionUtils.findField(Beer.class, "sdkId"); CouchbasePersistentProperty sdkIdProperty = getPropertyFor(sdkIdField); Field springIdField = ReflectionUtils.findField(Beer.class, "springId"); @@ -115,9 +124,20 @@ public class BasicCouchbasePersistentPropertyTests { //here this simulates the order in which the annotations would be found // when "overriding" Spring @Id with SDK's @Id... test.addPersistentProperty(springIdProperty); - assertEquals(springIdProperty, test.getIdProperty()); + + Optional property = test.getIdProperty(); + assertTrue(property.isPresent()); + property.ifPresent(actual -> { + assertEquals(springIdProperty, actual); + }); + test.addPersistentProperty(sdkIdProperty); - assertEquals(springIdProperty, test.getIdProperty()); + + property = test.getIdProperty(); + assertTrue(property.isPresent()); + property.ifPresent(actual -> { + assertEquals(springIdProperty, actual); + }); } /** @@ -127,8 +147,8 @@ public class BasicCouchbasePersistentPropertyTests { * @return the actual BasicCouchbasePersistentProperty instance. */ private CouchbasePersistentProperty getPropertyFor(Field field) { - return new BasicCouchbasePersistentProperty(field, null, entity, - new SimpleTypeHolder(), PropertyNameFieldNamingStrategy.INSTANCE); + return new BasicCouchbasePersistentProperty(Property.of(field), entity, new SimpleTypeHolder(), + PropertyNameFieldNamingStrategy.INSTANCE); } /** diff --git a/src/test/java/org/springframework/data/couchbase/repository/query/PartTreeN1qBasedQueryTest.java b/src/test/java/org/springframework/data/couchbase/repository/query/PartTreeN1qBasedQueryTest.java index 2c8788ad..ac569aaf 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/query/PartTreeN1qBasedQueryTest.java +++ b/src/test/java/org/springframework/data/couchbase/repository/query/PartTreeN1qBasedQueryTest.java @@ -8,6 +8,7 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Optional; import org.junit.Test; import org.springframework.data.couchbase.core.BeerDTO; @@ -60,6 +61,7 @@ public class PartTreeN1qBasedQueryTest { CouchbaseQueryMethod queryMethod = new CouchbaseQueryMethod(method, metadata, factory, mappingContext); + when(accessor.getSort()).thenReturn(Sort.unsorted()); when(entityInformation.getJavaType()).thenReturn(Beer.class); when(couchbaseOperations.getCouchbaseBucket()).thenReturn(couchbaseBucket); when(couchbaseBucket.name()).thenReturn("default"); @@ -139,9 +141,8 @@ public class PartTreeN1qBasedQueryTest { RepositoryMetadata metadata = new DefaultRepositoryMetadata(TestRepository.class); Method method = TestRepository.class.getMethod("findAllProjectedBy"); CouchbaseQueryMethod queryMethod = new CouchbaseQueryMethod(method, metadata, factory, mappingContext); - ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(accessor); - + when(accessor.getDynamicProjection()).thenReturn(Optional.of(BeerProjection.class)); when(entityInformation.getJavaType()).thenReturn(Beer.class); when(couchbaseOperations.getCouchbaseBucket()).thenReturn(couchbaseBucket); when(couchbaseBucket.name()).thenReturn("B"); @@ -150,6 +151,8 @@ public class PartTreeN1qBasedQueryTest { when(couchbaseConverter.getTypeKey()).thenReturn("_class"); when(couchbaseConverter.convertForWriteIfNeeded(eq("value"))).thenReturn("value"); + ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(Optional.of(accessor)); + PartTreeN1qlBasedQuery query = new PartTreeN1qlBasedQuery(queryMethod, couchbaseOperations); Statement statement = query.getStatement(accessor, null, processor.getReturnedType()); @@ -171,8 +174,8 @@ public class PartTreeN1qBasedQueryTest { Method method = TestRepository.class.getMethod("findAllDtoedBy"); MappingContext mappingContext = new CouchbaseMappingContext(); CouchbaseQueryMethod queryMethod = new CouchbaseQueryMethod(method, metadata, factory, mappingContext); - ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(accessor); + when(accessor.getDynamicProjection()).thenReturn(Optional.of(BeerDTO.class)); when(entityInformation.getJavaType()).thenReturn(Beer.class); when(couchbaseOperations.getCouchbaseBucket()).thenReturn(couchbaseBucket); when(couchbaseBucket.name()).thenReturn("B"); @@ -180,6 +183,8 @@ public class PartTreeN1qBasedQueryTest { when(couchbaseOperations.getConverter().getMappingContext()).thenReturn(mappingContext); when(couchbaseConverter.getTypeKey()).thenReturn("_class"); + ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(Optional.of(accessor)); + PartTreeN1qlBasedQuery query = new PartTreeN1qlBasedQuery(queryMethod, couchbaseOperations); Statement statement = query.getStatement(accessor, null, processor.getReturnedType());