Refactor spring-data-couchbase into modules.

This allows pulling CouchbaseAnnotationProcessor into its own module so
that javax.inject is not needed as a dependency for spring-data-couchbase.

Closes #1989.
This commit is contained in:
mikereiche
2024-10-15 14:12:34 -07:00
parent 756a8c5ae9
commit 8c9668cbec
566 changed files with 2335 additions and 259 deletions

188
pom.xml
View File

@@ -4,11 +4,12 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<artifactId>spring-data-couchbase-parent</artifactId>
<version>5.4.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Spring Data Couchbase</name>
<description>Spring Data integration for Couchbase</description>
<name>Spring Data Couchbase Parent</name>
<description>Spring Data integration for Couchbase - Parent</description>
<url>https://github.com/spring-projects/spring-data-couchbase</url>
<parent>
@@ -17,14 +18,12 @@
<version>3.4.0-SNAPSHOT</version>
</parent>
<properties>
<couchbase>3.7.4</couchbase>
<springdata.commons>3.4.0-SNAPSHOT</springdata.commons>
<java-module-name>spring.data.couchbase</java-module-name>
<hibernate.validator>7.0.1.Final</hibernate.validator>
<couchbase.encryption>3.1.0</couchbase.encryption>
<jodatime>2.10.13</jodatime>
<jackson-joda>2.13.4</jackson-joda>
<jakarta.el>4.0.0</jakarta.el>
</properties>
@@ -42,53 +41,6 @@
<dependencies>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl}</version>
<classifier>jakarta</classifier>
<exclusions>
<exclusion>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${springdata.commons}</version>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
<version>${couchbase}</version>
</dependency>
<!-- CDI -->
<dependency>
<groupId>jakarta.enterprise</groupId>
@@ -125,6 +77,7 @@
<scope>test</scope>
</dependency>
<!--
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
@@ -136,13 +89,16 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
-->
<!--
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime}</version>
<optional>true</optional>
</dependency>
-->
<dependency>
<groupId>org.testcontainers</groupId>
@@ -151,6 +107,7 @@
</dependency>
<!-- JSR 303 Validation -->
<!--
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
@@ -165,7 +122,9 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
-->
<!--
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
@@ -173,6 +132,7 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
-->
<!-- CDI -->
<!-- Dependency order required to build against CDI 1.0 and test with CDI 2.0 -->
@@ -247,116 +207,96 @@
<scope>test</scope>
</dependency>
<!--
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>couchbase-encryption</artifactId>
<version>${couchbase.encryption}</version>
<scope>test</scope>
</dependency>
-->
</dependencies>
<modules>
<module>spring-data-couchbase</module>
<module>spring-data-couchbase-querydsl</module>
<module>spring-data-couchbase-testutils</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<proc>none</proc>
</configuration>
<executions>
<execution>
<id>test-annotation-processing</id>
<phase>generate-test-sources</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<proc>only</proc>
<annotationProcessors>
<annotationProcessor>org.springframework.data.couchbase.repository.support.CouchbaseAnnotationProcessor</annotationProcessor>
</annotationProcessors>
<generatedTestSourcesDirectory>target/generated-test-sources</generatedTestSourcesDirectory>
<compilerArgs>
<arg>-Aquerydsl.logInfo=true</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
<useFile>false</useFile>
<trimStackTrace>false</trimStackTrace>
<includes>
<include>**/*.scala</include>
<include>**/*Spec.class</include>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IntegrationTests.java</exclude>
</excludes>
<excludedGroups>flaky</excludedGroups>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!--
<version>3.13.0</version>
-->
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.2</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>9.3</version>
</dependency>
</dependencies>
<configuration>
<useModulePath>false</useModulePath>
<includes>
<include>**/*IntegrationTest.java</include>
<include>**/*IntegrationTests.java</include>
</includes>
<headerLocation>config/checkstyle/checkstyle-header.txt</headerLocation>
<configLocation>config/checkstyle/checkstyle-basic.xml</configLocation>
<suppressionsLocation>config/checkstyle/checkstyle-suppressions.xml</suppressionsLocation>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<linkXRef>false</linkXRef>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
-->
<!-- Want java-fit-performer to be executable. Maven complains if use exec:java target as the dependencies of
module aren't executable. The workaround appears to be this - disable execution by default. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<legacyMode>true</legacyMode>
<skip>true</skip>
<executable>java</executable>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>antora-process-resources</id>
<build>
<resources>
<resource>
<directory>src/main/antora/resources/antora-resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</profile>
<profile>
<id>antora</id>
<build>
<plugins>
<plugin>
<groupId>org.antora</groupId>
<artifactId>antora-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>

View File

@@ -0,0 +1,214 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase-querydsl</artifactId>
<version>5.4.0-SNAPSHOT</version>
<name>Spring Data Couchbase Querydsl</name>
<description>Spring Data integration for Couchbase</description>
<url>https://github.com/spring-projects/spring-data-couchbase</url>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase-parent</artifactId>
<version>5.4.0-SNAPSHOT</version>
</parent>
<properties>
<couchbase>3.7.4</couchbase>
<springdata.commons>3.4.0-SNAPSHOT</springdata.commons>
<java-module-name>spring.data.couchbase</java-module-name>
<hibernate.validator>7.0.1.Final</hibernate.validator>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl}</version>
<classifier>jakarta</classifier>
<exclusions>
<exclusion>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>5.4.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase-testutils</artifactId>
<version>0.0.99</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
<version>${couchbase}</version>
</dependency>
<!-- JSR 303 Validation -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>${validation}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId>
<version>${jakarta.el}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>${jakarta.el}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<proc>none</proc>
</configuration>
<executions>
<execution>
<id>test-annotation-processing</id>
<phase>generate-test-sources</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<proc>only</proc>
<annotationProcessors>
<annotationProcessor>org.springframework.data.couchbase.repository.support.CouchbaseAnnotationProcessor</annotationProcessor>
</annotationProcessors>
<generatedTestSourcesDirectory>target/generated-test-sources</generatedTestSourcesDirectory>
<compilerArgs>
<arg>-Aquerydsl.logInfo=true</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
<useFile>false</useFile>
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IntegrationTests.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<useModulePath>false</useModulePath>
<includes>
<include>**/*IntegrationTest.java</include>
<include>**/*IntegrationTests.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<legacyMode>true</legacyMode>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>antora-process-resources</id>
<build>
<resources>
<resource>
<directory>src/main/antora/resources/antora-resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</profile>
</profiles>
<repositories>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>

View File

@@ -44,6 +44,7 @@ import com.querydsl.core.types.Predicate;
/**
* Couchbase-specific {@link QuerydslPredicateExecutor} that allows execution {@link Predicate}s in various forms.
* This is referenced by reflection in {@link CouchbaseRepositoryFactory}
*
* @author Michael Reiche
* @since 5.0
@@ -57,6 +58,7 @@ public class QuerydslCouchbasePredicateExecutor<T> extends QuerydslPredicateExec
* Creates a new {@link QuerydslCouchbasePredicateExecutor} for the given {@link CouchbaseEntityInformation} and
* {@link CouchbaseOperations}. Uses the {@link SimpleEntityPathResolver} to create an {@link EntityPath} for the
* given domain class.
* This is referenced by reflection in {@link CouchbaseRepositoryFactory}
*
* @param entityInformation must not be {@literal null}.
* @param couchbaseOperations must not be {@literal null}.

View File

@@ -0,0 +1,207 @@
/*
* Copyright 2012-2024 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
*
* https://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.data.couchbase.domain;
import java.lang.reflect.InvocationTargetException;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.data.couchbase.CouchbaseClientFactory;
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService;
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.repository.auditing.EnableCouchbaseAuditing;
import org.springframework.data.couchbase.repository.auditing.EnableReactiveCouchbaseAuditing;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
import org.springframework.data.couchbase.repository.config.EnableReactiveCouchbaseRepositories;
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.DeserializationFeature;
import com.couchbase.client.core.deps.io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import com.couchbase.client.core.env.SecurityConfig;
import com.couchbase.client.java.env.ClusterEnvironment;
import com.couchbase.client.java.json.JacksonTransformers;
/**
* @author Michael Nitschinger
* @author Michael Reiche
* @author Jorge Rodriguez Martin
* @since 3.0
*/
@Configuration
@EnableCouchbaseRepositories
@EnableReactiveCouchbaseRepositories
@EnableCouchbaseAuditing(dateTimeProviderRef = "dateTimeProviderRef")
@EnableReactiveCouchbaseAuditing(dateTimeProviderRef = "dateTimeProviderRef")
@EnableCaching
public class Config extends AbstractCouchbaseConfiguration {
String bucketname = "travel-sample";
String username = "Administrator";
String password = "password";
String connectionString = "127.0.0.1";
// if running a clusterAwareIntegrationTests, use those properties
static Class clusterAware = null;
static {
try {
clusterAware = Class.forName("org.springframework.data.couchbase.util.ClusterAwareIntegrationTests");
if (clusterAware.getMethod("config").invoke(null) == null)
clusterAware = null;
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
String clusterGet(String methodName, String defaultValue) {
if (clusterAware != null) {
try {
return (String) clusterAware.getMethod(methodName).invoke(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return defaultValue;
}
@Override
public String getConnectionString() {
return clusterGet("connectionString", connectionString);
}
@Override
public String getUserName() {
return clusterGet("username", username);
}
@Override
public String getPassword() {
return clusterGet("password", password);
}
@Override
public String getBucketName() {
return clusterGet("bucketName", bucketname);
}
@Override
protected void configureEnvironment(ClusterEnvironment.Builder builder) {
if (getConnectionString().contains("cloud.couchbase.com")) {
builder.securityConfig(
SecurityConfig.builder().trustManagerFactory(InsecureTrustManagerFactory.INSTANCE).enableTls(true));
}
}
@Override
public void configureReactiveRepositoryOperationsMapping(ReactiveRepositoryOperationsMapping baseMapping) {
try {
// comment out references to 'protected' and 'mybucket' - they are only to show how multi-bucket would work
// ReactiveCouchbaseTemplate personTemplate = myReactiveCouchbaseTemplate(myCouchbaseClientFactory("protected"),
// (MappingCouchbaseConverter) (baseMapping.getDefault().getConverter()));
// baseMapping.mapEntity(Person.class, personTemplate); // Person goes in "protected" bucket
// ReactiveCouchbaseTemplate userTemplate = myReactiveCouchbaseTemplate(myCouchbaseClientFactory("mybucket"),
// (MappingCouchbaseConverter) (baseMapping.getDefault().getConverter()));
// baseMapping.mapEntity(User.class, userTemplate); // User goes in "mybucket"
// everything else goes in getBucketName() ( which is travel-sample )
} catch (Exception e) {
throw e;
}
}
@Override
public void configureRepositoryOperationsMapping(RepositoryOperationsMapping baseMapping) {
try {
// comment out references to 'protected' and 'mybucket' - they are only to show how multi-bucket would work
// CouchbaseTemplate personTemplate = myCouchbaseTemplate(myCouchbaseClientFactory("protected"),
// (MappingCouchbaseConverter) (baseMapping.getDefault().getConverter()));
// baseMapping.mapEntity(Person.class, personTemplate); // Person goes in "protected" bucket
// MappingCouchbaseConverter cvtr = (MappingCouchbaseConverter)baseMapping.getDefault().getConverter();
// CouchbaseTemplate userTemplate = myCouchbaseTemplate(myCouchbaseClientFactory("mybucket"),
// (MappingCouchbaseConverter) (baseMapping.getDefault().getConverter()));
// baseMapping.mapEntity(User.class, userTemplate); // User goes in "mybucket"
// everything else goes in getBucketName() ( which is travel-sample )
} catch (Exception e) {
throw e;
}
}
// do not use reactiveCouchbaseTemplate for the name of this method, otherwise the value of that bean
// will be used instead of the result of this call (the client factory arg is different)
public ReactiveCouchbaseTemplate myReactiveCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
MappingCouchbaseConverter mappingCouchbaseConverter) {
return new ReactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter,
new JacksonTranslationService(), getDefaultConsistency());
}
// do not use couchbaseTemplate for the name of this method, otherwise the value of that been
// will be used instead of the result from this call (the client factory arg is different)
public CouchbaseTemplate myCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
MappingCouchbaseConverter mappingCouchbaseConverter) {
return new CouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter, new JacksonTranslationService(),
getDefaultConsistency());
}
// do not use couchbaseClientFactory for the name of this method, otherwise the value of that bean will
// will be used instead of this call being made ( bucketname is an arg here, instead of using bucketName() )
public CouchbaseClientFactory myCouchbaseClientFactory(String bucketName) {
return new SimpleCouchbaseClientFactory(getConnectionString(), authenticator(), bucketName);
}
@Override
@Bean(name = "couchbaseTranslationService")
public TranslationService couchbaseTranslationService() {
final JacksonTranslationService jacksonTranslationService = new JacksonTranslationService();
jacksonTranslationService.afterPropertiesSet();
// for sdk3, we need to ask the mapper _it_ uses to ignore extra fields...
JacksonTransformers.MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return jacksonTranslationService;
}
@Bean
public CouchbaseCacheManager cacheManager(CouchbaseTemplate couchbaseTemplate) throws Exception {
CouchbaseCacheManager.CouchbaseCacheManagerBuilder builder = CouchbaseCacheManager.CouchbaseCacheManagerBuilder
.fromConnectionFactory(couchbaseTemplate.getCouchbaseClientFactory());
return builder.build();
}
@Override
public String typeKey() {
return "t"; // this will override '_class', is passed in to new CustomMappingCouchbaseConverter
}
static String scopeName = null;
@Override
protected String getScopeName() {
return scopeName;
}
}

View File

@@ -24,10 +24,12 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;
import org.springframework.data.couchbase.core.query.QueryCriteriaDefinition;
import org.springframework.data.couchbase.domain.*;
import org.springframework.data.couchbase.domain.time.AuditingDateTimeProvider;
import org.springframework.data.couchbase.repository.auditing.EnableCouchbaseAuditing;
import org.springframework.data.couchbase.repository.auditing.EnableReactiveCouchbaseAuditing;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
@@ -621,6 +623,21 @@ public class CouchbaseRepositoryCollectionQuerydslIntegrationTests extends Colle
public ValidatingCouchbaseEventListener validationEventListener() {
return new ValidatingCouchbaseEventListener(validator());
}
@Bean(name = "auditorAwareRef")
public NaiveAuditorAware testAuditorAware() {
return new NaiveAuditorAware();
}
@Bean(name = "reactiveAuditorAwareRef")
public ReactiveNaiveAuditorAware testReactiveAuditorAware() {
return new ReactiveNaiveAuditorAware();
}
@Bean(name = "dateTimeProviderRef")
public DateTimeProvider testDateTimeProvider() {
return new AuditingDateTimeProvider();
}
}
String bq(Predicate predicate) {

View File

@@ -39,12 +39,16 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;
import org.springframework.data.couchbase.core.query.QueryCriteriaDefinition;
import org.springframework.data.couchbase.domain.Airline;
import org.springframework.data.couchbase.domain.AirlineRepository;
import org.springframework.data.couchbase.domain.NaiveAuditorAware;
import org.springframework.data.couchbase.domain.QAirline;
import org.springframework.data.couchbase.domain.ReactiveNaiveAuditorAware;
import org.springframework.data.couchbase.domain.time.AuditingDateTimeProvider;
import org.springframework.data.couchbase.repository.auditing.EnableCouchbaseAuditing;
import org.springframework.data.couchbase.repository.auditing.EnableReactiveCouchbaseAuditing;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
@@ -633,6 +637,20 @@ public class CouchbaseRepositoryQuerydslIntegrationTests extends JavaIntegration
public ValidatingCouchbaseEventListener validationEventListener() {
return new ValidatingCouchbaseEventListener(validator());
}
@Bean(name = "auditorAwareRef")
public NaiveAuditorAware testAuditorAware() {
return new NaiveAuditorAware();
}
@Bean(name = "reactiveAuditorAwareRef")
public ReactiveNaiveAuditorAware testReactiveAuditorAware() {
return new ReactiveNaiveAuditorAware();
}
@Bean(name = "dateTimeProviderRef")
public DateTimeProvider testDateTimeProvider() {
return new AuditingDateTimeProvider();
}
}
String bq(Predicate predicate) {

View File

@@ -12,6 +12,7 @@ cluster.mocked.numReplicas=1
cluster.unmanaged.seed=127.0.0.1:8091
cluster.adminUsername=Administrator
cluster.adminPassword=password
#cluster.bucket=my_bucket
#cluster.unmanaged.seed=cb.zsibzkbgllfbcj8g.cloud.couchbase.com
#cluster.adminUsername=user
#cluster.adminPassword=Couch0base!

View File

@@ -0,0 +1,283 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase-testutils</artifactId>
<version>0.0.99</version>
<name>Spring Data Couchbase Test-Utils</name>
<description>Spring Data integration for Couchbase</description>
<url>https://github.com/spring-projects/spring-data-couchbase</url>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase-parent</artifactId>
<version>5.4.0-SNAPSHOT</version>
</parent>
<properties>
<couchbase>3.7.4</couchbase>
<springdata.commons>3.4.0-SNAPSHOT</springdata.commons>
<jodatime>2.10.13</jodatime>
<jackson-joda>2.13.4</jackson-joda>
<jakarta.el>4.0.0</jakarta.el>
<junit.version>5.9.1</junit.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl}</version>
<classifier>jakarta</classifier>
<exclusions>
<exclusion>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${springdata.commons}</version>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
<version>${couchbase}</version>
</dependency>
<!-- CDI -->
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>${cdi}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring}</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.1.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${jackson-joda}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
</dependency>
<!-- JSR 303 Validation -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>${validation}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId>
<version>${jakarta.el}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>${jakarta.el}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- CDI -->
<!-- Dependency order required to build against CDI 1.0 and test with CDI 2.0 -->
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jcdi_2.0_spec</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>1.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-se</artifactId>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.couchbase.mock</groupId>
<artifactId>CouchbaseMock</artifactId>
<version>1.5.25</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.8.1</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-tls</artifactId>
<version>4.8.1</version>
</dependency>
<!-- Kotlin extension -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.0.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>

View File

@@ -28,6 +28,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import com.couchbase.client.java.ClusterOptions;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
@@ -36,8 +37,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.CouchbaseClientFactory;
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
import com.couchbase.client.core.deps.io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import com.couchbase.client.core.env.Authenticator;
@@ -56,7 +55,6 @@ import com.couchbase.client.java.transactions.config.TransactionsConfig;
* Parent class which drives all dynamic integration tests based on the configured cluster setup.
*
* @author Michael Reiche
*
* @since 2.0.0
*/
@ExtendWith(ClusterInvocationProvider.class)
@@ -71,28 +69,24 @@ public abstract class ClusterAwareIntegrationTests {
static void setup(TestClusterConfig config) {
testClusterConfig = config;
// Disabling cleanupLostAttempts to simplify output during development
ClusterEnvironment env = ClusterEnvironment.builder()
.transactionsConfig(TransactionsConfig.cleanupConfig(TransactionsCleanupConfig.cleanupLostAttempts(false)))
.build();
ClusterEnvironment env = ClusterEnvironment.builder().transactionsConfig(
TransactionsConfig.cleanupConfig(TransactionsCleanupConfig.cleanupLostAttempts(false))).build();
String connectString = connectionString();
Cluster tmpCluster = null;
try (CouchbaseClientFactory couchbaseClientFactory = new SimpleCouchbaseClientFactory(connectString,
authenticator(), bucketName(), null, env)) {
tmpCluster = couchbaseClientFactory.getCluster();
couchbaseClientFactory.getCluster().queryIndexes().createPrimaryIndex(bucketName(), CreatePrimaryQueryIndexOptions
Cluster tmpCluster = null;
try (Cluster cluster = Cluster.connect(connectString,
ClusterOptions.clusterOptions(authenticator()).environment(env))) {
cluster.queryIndexes().createPrimaryIndex(bucketName(), CreatePrimaryQueryIndexOptions
.createPrimaryQueryIndexOptions().ignoreIfExists(true).timeout(Duration.ofSeconds(300)));
// this is for the N1qlJoin test
List<String> fieldList = new ArrayList<>();
fieldList.add("parentId");
couchbaseClientFactory.getCluster().queryIndexes().createIndex(bucketName(), "parent_idx", fieldList,
CreateQueryIndexOptions.createQueryIndexOptions().ignoreIfExists(true).timeout(Duration.ofSeconds(300)));
cluster.queryIndexes().createIndex(bucketName(), "parent_idx", fieldList, CreateQueryIndexOptions
.createQueryIndexOptions().ignoreIfExists(true).timeout(Duration.ofSeconds(300)));
// .with("_class", "org.springframework.data.couchbase.domain.Address"));
logCluster(couchbaseClientFactory.getCluster(), "$");
logCluster(cluster, "$");
} catch (IndexFailureException ife) {
LOGGER.warn("IndexFailureException occurred - ignoring: ", ife);
logDisconnect(tmpCluster, "IndexFailureException");
} catch (IOException ioe) {
throw new RuntimeException(ioe);
logDisconnect(tmpCluster, "IndexFailureException");
}
}
@@ -156,86 +150,88 @@ public abstract class ClusterAwareIntegrationTests {
*/
protected static ClusterEnvironment.Builder environment() {
return config().isUsingCloud()
? ClusterEnvironment.builder()
.securityConfig(SecurityConfig.trustManagerFactory(InsecureTrustManagerFactory.INSTANCE).enableTls(true))
? ClusterEnvironment.builder().securityConfig(
SecurityConfig.trustManagerFactory(InsecureTrustManagerFactory.INSTANCE).enableTls(true))
: ClusterEnvironment.builder();
}
protected static Set<SeedNode> seedNodes() {
return config().nodes().stream().map(cfg -> SeedNode.create(cfg.hostname(),
Optional.ofNullable(config().isUsingCloud() ? cfg.ports().get(Services.KV_TLS) : cfg.ports().get(Services.KV)),
Optional.ofNullable(
config().isUsingCloud() ? cfg.ports().get(Services.MANAGER_TLS) : cfg.ports().get(Services.MANAGER))))
return config().nodes().stream()
.map(cfg -> SeedNode.create(cfg.hostname(),
Optional.ofNullable(config().isUsingCloud() ? cfg.ports().get(Services.KV_TLS)
: cfg.ports().get(Services.KV)),
Optional.ofNullable(config().isUsingCloud() ? cfg.ports().get(Services.MANAGER_TLS)
: cfg.ports().get(Services.MANAGER))))
.collect(Collectors.toSet());
}
static Set<String> flagged = new HashSet<>();
static Set<String> flagged = new HashSet<>();
@AfterEach
public void afterEach() {
if (clusterToDisconnect == null && !flagged.contains(this.getClass().getSimpleName())) {
flagged.add(this.getClass().getSimpleName());
logMessage("CoreDisconnected:\"coreId\":\"" + this.getClass().getSimpleName() + "\"");
}
}
@AfterEach
public void afterEach() {
if (clusterToDisconnect == null && !flagged.contains(this.getClass().getSimpleName())) {
flagged.add(this.getClass().getSimpleName());
logMessage("CoreDisconnected:\"coreId\":\"" + this.getClass().getSimpleName() + "\"");
}
}
@AfterAll
public static void afterAll() {
//if (clusterToDisconnect != null) {
// logDisconnect(clusterToDisconnect, "$");
// clusterToDisconnect = null;
//} else {
// already flaged by afterEach
//}
logMessage("CoreDisconnected:\"coreId\":\"------------------\"");
callSuperAfterAll(new Object() {});
}
@AfterAll
public static void afterAll() {
// if (clusterToDisconnect != null) {
// logDisconnect(clusterToDisconnect, "$");
// clusterToDisconnect = null;
// } else {
// already flaged by afterEach
// }
logMessage("CoreDisconnected:\"coreId\":\"------------------\"");
callSuperAfterAll(new Object() {});
}
static Set<Long> disconnectedMap = new HashSet<>();
static Set<Long> disconnectedMap = new HashSet<>();
public static void logCluster(Cluster cluster, String s) {
if (cluster == null || disconnectedMap.contains(cluster.core().context().id())) {
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info("CoreDisconnectedAutoAlready:\"coreId\":\""
+ String.format("0x%16x", 0) + "auto missed<" + s + ">\"");
} else {
disconnectedMap.add(cluster.core().context().id());
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info("CoreDisconnectedAuto:\"coreId\":\""
+ String.format("0x%x", cluster.core().context().id()) + "(" + s + ")\"");
//cluster.environment().shutdown(Duration.ofSeconds(60)); needs to happend after auto disconnect()
}
}
public static void logCluster(Cluster cluster, String s) {
if (cluster == null || disconnectedMap.contains(cluster.core().context().id())) {
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info("CoreDisconnectedAutoAlready:\"coreId\":\""
+ String.format("0x%16x", 0) + "auto missed<" + s + ">\"");
} else {
disconnectedMap.add(cluster.core().context().id());
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info("CoreDisconnectedAuto:\"coreId\":\""
+ String.format("0x%x", cluster.core().context().id()) + "(" + s + ")\"");
// cluster.environment().shutdown(Duration.ofSeconds(60)); needs to happend after auto disconnect()
}
}
public static void logDisconnect(Cluster cluster, String s) {
if (cluster == null || disconnectedMap.contains(cluster.core().context().id())) {
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info(
"CoreDisconnectedAlready:\"coreId\":\"" + String.format("0x%16x", 0) + " missed{" + s + "}\"");
} else {
disconnectedMap.add(cluster.core().context().id());
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info("CoreDisconnected:\"coreId\":\""
+ String.format("0x%x", cluster.core().context().id()) + "[" + s + "]\"");
cluster.disconnect();
cluster.environment().shutdown(Duration.ofSeconds(60));
}
}
public static void logDisconnect(Cluster cluster, String s) {
if (cluster == null || disconnectedMap.contains(cluster.core().context().id())) {
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info(
"CoreDisconnectedAlready:\"coreId\":\"" + String.format("0x%16x", 0) + " missed{" + s + "}\"");
} else {
disconnectedMap.add(cluster.core().context().id());
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info("CoreDisconnected:\"coreId\":\""
+ String.format("0x%x", cluster.core().context().id()) + "[" + s + "]\"");
cluster.disconnect();
cluster.environment().shutdown(Duration.ofSeconds(60));
}
}
public static void logMessage(String message) {
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info(message);
}
public static void logMessage(String message) {
org.slf4j.LoggerFactory.getLogger("com.couchbase.core").info(message);
}
@BeforeAll()
public static void beforeAll() {}
@BeforeEach
public void beforeEach() {
clusterToDisconnect = cluster;
}
public void beforeEach() {
clusterToDisconnect = cluster;
}
/**
* This should probably be the first call in the @BeforeAll method of a test class. This will call super @BeforeAll
* methods when called as callSuperBeforeAll(new Object() {}); this trickery is necessary because super.beforeAll()
* cannot be used because it is a static method. it is possible and likely that the beforeAll() method of should still
* be called even when a test class defines its own beforeAll() method which would hide the beforeAll() of the super
* class. This trickery is not necessary for before/AfterEach, as those are not static methods
* cannot be used because it is a static method. it is possible and likely that the beforeAll() method of should
* still be called even when a test class defines its own beforeAll() method which would hide the beforeAll() of the
* super class. This trickery is not necessary for before/AfterEach, as those are not static methods
*
* @Author Michael Reiche
* @param createdHere - an object from a class defined in the calling class

View File

@@ -21,7 +21,6 @@ import java.util.List;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.springframework.data.couchbase.domain.Config;
import com.couchbase.client.core.error.IndexExistsException;
import com.couchbase.client.core.service.ServiceType;
@@ -46,10 +45,9 @@ public class CollectionAwareDefaultScopeIntegrationTests extends JavaIntegration
@BeforeAll
public static void beforeAll() {
callSuperBeforeAll(new Object() {
});
callSuperBeforeAll(new Object() {});
Cluster cluster = Cluster.connect(connectionString(),
ClusterOptions.clusterOptions(authenticator()).environment(environment().build()));
ClusterOptions.clusterOptions(authenticator()).environment(environment().build()));
Bucket bucket = cluster.bucket(config().bucketname());
bucket.waitUntilReady(Duration.ofSeconds(30));
waitForService(bucket, ServiceType.QUERY);
@@ -66,33 +64,31 @@ public class CollectionAwareDefaultScopeIntegrationTests extends JavaIntegration
try {
// needs an index for this N1ql Join
// create index ix2 on my_bucket(parent_id) where `_class` = 'org.springframework.data.couchbase.domain.Address';
// create index ix2 on my_bucket(parent_id) where `_class` =
// 'org.springframework.data.couchbase.domain.Address';
List<String> fieldList = new ArrayList<>();
fieldList.add("parentId");
cluster.query("CREATE INDEX `parent_idx` ON default:`" + bucketName() + "`." + scopeName + "." + collectionName2
+ "(parentId)");
cluster.query("CREATE INDEX `parent_idx` ON default:`" + bucketName() + "`." + scopeName + "."
+ collectionName2 + "(parentId)");
} catch (IndexExistsException ife) {
LOGGER.warn("IndexFailureException occurred - ignoring: ", ife.toString());
}
logDisconnect(cluster, CollectionAwareDefaultScopeIntegrationTests.class.getSimpleName());
Config.setScopeName(scopeName);
// ApplicationContext ac = new AnnotationConfigApplicationContext();
// System.out.println(ac);
logDisconnect(cluster, CollectionAwareDefaultScopeIntegrationTests.class.getSimpleName());
// ApplicationContext ac = new AnnotationConfigApplicationContext();
// System.out.println(ac);
// the Config class has been modified, these need to be loaded again
// couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
// reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
// couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
// reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
}
@AfterAll
public static void afterAll() {
Config.setScopeName(null);
// ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
// ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
// the Config class has been modified, these need to be loaded again
// couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
// reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
callSuperAfterAll(new Object() {
});
// couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
// reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
callSuperAfterAll(new Object() {});
}
}

View File

@@ -21,7 +21,6 @@ import java.util.List;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.springframework.data.couchbase.domain.Config;
import com.couchbase.client.core.error.IndexExistsException;
import com.couchbase.client.core.service.ServiceType;
@@ -64,31 +63,30 @@ public class CollectionAwareIntegrationTests extends JavaIntegrationTests {
try {
// needs an index for this N1ql Join
// create index ix2 on my_bucket(parent_id) where `_class` = 'org.springframework.data.couchbase.domain.Address';
// create index ix2 on my_bucket(parent_id) where `_class` =
// 'org.springframework.data.couchbase.domain.Address';
List<String> fieldList = new ArrayList<>();
fieldList.add("parentId");
cluster.query("CREATE INDEX `parent_idx` ON default:`" + bucketName() + "`." + scopeName + "." + collectionName2
+ "(parentId)");
cluster.query("CREATE INDEX `parent_idx` ON default:`" + bucketName() + "`." + scopeName + "."
+ collectionName2 + "(parentId)");
} catch (IndexExistsException ife) {
LOGGER.warn("IndexFailureException occurred - ignoring: ", ife.toString());
}
logDisconnect(cluster, CollectionAwareIntegrationTests.class.getSimpleName());
Config.setScopeName(scopeName);
// ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
// System.out.println(ac);
logDisconnect(cluster, CollectionAwareIntegrationTests.class.getSimpleName());
// ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
// System.out.println(ac);
// the Config class has been modified, these need to be loaded again
// couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
// reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
// couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
// reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
}
@AfterAll
public static void afterAll() {
Config.setScopeName(null);
// ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
// ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
// the Config class has been modified, these need to be loaded again
// couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
// reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
// couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
// reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
callSuperAfterAll(new Object() {});
}
}

View File

@@ -25,7 +25,6 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.springframework.data.couchbase.util.Util.waitUntilCondition;
import java.io.IOException;
import java.time.Duration;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -42,9 +41,6 @@ import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.function.Executable;
import org.junit.platform.commons.util.UnrecoverableExceptions;
import org.opentest4j.AssertionFailedError;
import org.springframework.data.couchbase.CouchbaseClientFactory;
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
import org.springframework.data.couchbase.domain.Config;
import org.springframework.data.couchbase.transactions.SimulateFailureException;
import com.couchbase.client.core.diagnostics.PingResult;
@@ -92,15 +88,13 @@ public class JavaIntegrationTests extends ClusterAwareIntegrationTests {
@BeforeAll
public static void beforeAll() {
Config.setScopeName(null);
//Config.setScopeName(null);
callSuperBeforeAll(new Object() {});
try (CouchbaseClientFactory couchbaseClientFactory = new SimpleCouchbaseClientFactory(connectionString(),
authenticator(), bucketName())) {
couchbaseClientFactory.getCluster().queryIndexes().createPrimaryIndex(bucketName(),
try (Cluster cluster = Cluster.connect(connectionString(),
username(), password())) {
cluster.queryIndexes().createPrimaryIndex(bucketName(),
CreatePrimaryQueryIndexOptions.createPrimaryQueryIndexOptions().ignoreIfExists(true));
logCluster(couchbaseClientFactory.getCluster(), "-");
} catch (IOException ioe) {
throw new RuntimeException(ioe);
logCluster(cluster, "-");
}
}

View File

@@ -0,0 +1,34 @@
= Continuous Integration
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-couchbase%2Fmain&subject=Moore%20(main)["Spring Data Couchbase", link="https://jenkins.spring
.io/view/SpringData/job/spring-data-couchbase/"]
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-couchbase%2F3.1.x&subject=Lovelace%20(3.1.x)["Spring Data Couchbase", link="https://jenkins.spring
.io/view/SpringData/job/spring-data-couchbase/"]
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-couchbase%2F2.2.x&subject=Ingalls%20(2.2.x)["Spring Data Couchbase", link="https://jenkins.spring
.io/view/SpringData/job/spring-data-couchbase/"]
== Running CI tasks locally
Since this pipeline is purely Docker-based, it's easy to:
* Debug what went wrong on your local machine.
* Test out a a tweak to your `test.sh` script before sending it out.
* Experiment against a new image before submitting your pull request.
All of these use cases are great reasons to essentially run what the CI server does on your local machine.
IMPORTANT: To do this you must have Docker installed on your machine.
1. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-couchbase-github -v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock adoptopenjdk/openjdk8:latest /bin/bash`
+
This will launch the Docker image and mount your source code at `spring-data-couchbase-github`.
+
2. `cd spring-data-couchbase-github`
+
Next, test everything from inside the container:
+
3. `./mvnw -Pci clean dependency:list test -Dsort -B` (or whatever test configuration you must use)
Since the container is binding to your source, you can make edits from your IDE and continue to run build jobs.
NOTE: Docker containers can eat up disk space fast! From time to time, run `docker system prune` to clean out old images.

View File

@@ -0,0 +1,3 @@
= Spring Data contribution guidelines
You find the contribution guidelines for Spring Data projects https://github.com/spring-projects/spring-data-build/blob/main/CONTRIBUTING.adoc[here].

130
spring-data-couchbase/Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,130 @@
def p = [:]
node {
checkout scm
p = readProperties interpolate: true, file: 'ci/pipeline.properties'
}
pipeline {
agent none
triggers {
pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS)
}
options {
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '14'))
}
stages {
stage("test: baseline (main)") {
when {
beforeAgent(true)
anyOf {
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
steps {
script {
docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
sh "PROFILE=ci JENKINS_USER_NAME=${p['jenkins.user.name']} ci/test.sh"
sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
}
}
}
}
}
stage("Test other configurations") {
when {
beforeAgent(true)
allOf {
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
parallel {
stage("test: baseline (next)") {
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
steps {
script {
docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
docker.image(p['docker.java.next.image']).inside(p['docker.java.inside.docker']) {
sh "PROFILE=ci JENKINS_USER_NAME=${p['jenkins.user.name']} ci/test.sh"
sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
}
}
}
}
}
}
}
stage('Release to artifactory') {
when {
beforeAgent(true)
anyOf {
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
agent {
label 'data'
}
options { timeout(time: 20, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
steps {
script {
docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
sh 'MAVEN_OPTS="-Duser.name=' + "${p['jenkins.user.name']}" + ' -Duser.home=/tmp/jenkins-home" ' +
"./mvnw -s settings.xml -Pci,artifactory " +
"-Ddevelocity.storage.directory=/tmp/jenkins-home/.develocity-root " +
"-Dartifactory.server=${p['artifactory.url']} " +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
"-Dartifactory.staging-repository=${p['artifactory.repository.snapshot']} " +
"-Dartifactory.build-name=spring-data-couchbase " +
"-Dartifactory.build-number=spring-data-couchbase-${BRANCH_NAME}-build-${BUILD_NUMBER} " +
"-Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-couchbase " +
"-Dmaven.test.skip=true clean deploy -U -B"
}
}
}
}
}
}
post {
changed {
script {
emailext(
subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}",
mimeType: 'text/html',
recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'RequesterRecipientProvider']],
body: "<a href=\"${env.BUILD_URL}\">${currentBuild.fullDisplayName} is reported as ${currentBuild.currentResult}</a>")
}
}
}
}

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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
https://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.

View File

@@ -0,0 +1,209 @@
= Spring Data Couchbase image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-couchbase%2Fmain&subject=Build[link=https://jenkins.spring.io/view/SpringData/job/spring-data-couchbase/] https://gitter.im/spring-projects/spring-data[image:https://badges.gitter.im/spring-projects/spring-data.svg[Gitter]] image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Develocity", link="https://ge.spring.io/scans?search.rootProjectNames=Spring Data Couchbase"]
The primary goal of the https://www.springsource.org/spring-data[Spring Data] project is to make it easier to build
Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce
frameworks, and cloud based data services.
The Spring Data Couchbase project aims to provide a familiar and consistent Spring-based programming model for Couchbase
Server as a document database and cache while retaining store-specific features and capabilities. Key functional areas
of Spring Data Couchbase are a POJO centric model for interacting with a Couchbase Server Bucket and easily writing a
repository style data access layer.
Integration tests require a couchbase server with a bucket name "protected" with "password" as the password set.
If the server allows users, then an user with username "protected" with "password" as the password should also be set.
The recommended way to run tests is to install docker and use container in server.properties.
This project is lead and maintained by Couchbase, Inc.
== Features
* Spring configuration support using Java based `@Configuration` classes or an XML namespace for the Couchbase driver (Java SDK version 2.x).
* `CouchbaseTemplate` helper class that increases productivity performing common Couchbase operations. Includes integrated object mapping between documents and POJOs.
* Exception translation into Springs portable Data Access Exception hierarchy.
* Feature Rich Object Mapping integrated with Springs Conversion Service.
* Annotation based mapping metadata but extensible to support other metadata formats.
* Automatic implementation of `Repository` interfaces including support for custom finder methods (backed by Couchbases query language, `N1QL`) and `PagingAndSortingRepository`.
* For Couchbase server versions < 4.0, repositories can still be backed by Couchbase Views.
* Support for geospatial and multidimensional querying (backed by Couchbase Spatial Views)
* JMX administration and monitoring
* Can serve as the backend for `@Cacheable` support, to cache any objects you need for high performance access (see sibling Spring Cache project in Couchbases github, https://github.com/couchbaselabs/couchbase-spring-cache[couchbaselabs/couchbase-spring-cache]).
== Version compatibility
`Spring-Data Couchbase` is the Spring Data connector for the `Couchbase Java SDK 2.x` generation.
Both the SDK and this Spring Data community project are major version changes with lots of differences from their respective previous versions.
Notably, this version is compatible with `Couchbase Server 4.0`, bringing support for the `N1QL` query language.
== Code of Conduct
This project is governed by the https://github.com/spring-projects/.github/blob/e3cc2ff230d8f1dca06535aa6b5a4a23815861d4/CODE_OF_CONDUCT.md[Spring Code of Conduct].By participating, you are expected to uphold this code of conduct.Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
== Getting Started
Here is a quick teaser of an application using Spring Data Repositories in Java:
[source,java]
----
public interface PersonRepository extends CrudRepository<Person, Long> {
List<Person> findByLastname(String lastname);
List<Person> findByFirstnameLike(String firstname);
}
@Service
public class MyService {
private final PersonRepository repository;
public MyService(PersonRepository repository) {
this.repository = repository;
}
public void doWork() {
repository.deleteAll();
Person person = new Person();
person.setFirstname("Couch");
person.setLastname("Base");
repository.save(person);
List<Person> lastNameResults = repository.findByLastname("Base");
List<Person> firstNameResults = repository.findByFirstnameLike("Cou*");
}
}
@Configuration
@EnableCouchbaseRepositories
public class Config extends AbstractCouchbaseConfiguration {
@Override
protected List<String> getBootstrapHosts() {
return Arrays.asList("host1", "host2");
}
@Override
protected String getBucketName() {
return "default";
}
@Override
protected String getPassword() {
return "";
}
}
----
=== Maven configuration
Add the Maven dependency:
[source,xml]
----
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>${version}</version>
</dependency>
----
If you'd rather like the latest snapshots of the upcoming major version, use our Maven snapshot repository and declare the appropriate dependency version.
[source,xml]
----
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>${version}-SNAPSHOT</version>
</dependency>
<repository>
<id>spring-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>https://repo.spring.io/snapshot</url>
</repository>
----
== Getting Help
Having trouble with Spring Data? Wed love to help!
* Check the
https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/[reference documentation], and https://docs.spring.io/spring-data/couchbase/docs/current/api/[Javadocs].
* Learn the Spring basics Spring Data builds on Spring Framework, check the https://spring.io[spring.io] web-site for a wealth of reference documentation.
If you are just starting out with Spring, try one of the https://spring.io/guides[guides].
* Ask a question - we monitor https://stackoverflow.com[stackoverflow.com] for questions tagged with https://stackoverflow.com/tags/spring-data[`spring-data-couchbase`].
You can also chat with the community on https://gitter.im/spring-projects/spring-data[Gitter].
* Report bugs with Spring Data Couchbase at https://jira.spring.io/browse/DATACOUCH[jira.spring.io/browse/DATACOUCH].
== Reporting Issues
Spring Data uses GitHub as issue tracking system to record bugs and feature requests.
If you want to raise an issue, please follow the recommendations below:
* Before you log a bug, please search the
https://github.com/spring-projects/spring-data-couchbase/issues[issue tracker] to see if someone has already reported the problem.
* If the issue does not already exist, https://github.com/spring-projects/spring-data-couchbase/issues/new[create a new issue].
* Please provide as much information as possible with the issue report, we like to know the version of Spring Data that you are using and JVM version.
* If you need to paste code, or include a stack trace use Markdown +++```+++ escapes before and after your text.
* If possible try to create a test-case or project that replicates the issue.
Attach a link to your code or a compressed file containing your code.
== Building from Source
You dont need to build from source to use Spring Data (binaries in https://repo.spring.io[repo.spring.io]), but if you want to try out the latest and greatest, Spring Data can be easily built with the https://github.com/takari/maven-wrapper[maven wrapper].
You also need JDK 17 or above.
[source,bash]
----
$ ./mvnw clean install
----
If you want to build with the regular `mvn` command, you will need https://maven.apache.org/run-maven/index.html[Maven v3.5.0 or above].
_Also see link:CONTRIBUTING.adoc[CONTRIBUTING.adoc] if you wish to submit pull requests, and in particular please sign the https://cla.pivotal.io/sign/spring[Contributors Agreement] before your first non-trivial change._
=== Building reference documentation
Building the documentation builds also the project without running tests.
[source,bash]
----
$ ./mvnw clean install -Pantora
----
The generated documentation is available from `target/antora/site/index.html`.
=== Building and staging reference documentation for review
[source,bash]
----
export MY_GIT_USER=<github-user>
mvn generate-resources
docs=`pwd`/target/site/reference/html
pushd /tmp
mkdir $$
cd $$
# see https://docs.github.com/en/pages/getting-started-with-github-pages/creating-a-github-pages-site
# this examples uses a repository named "staged"
git clone git@github.com:${MY_GIT_USER}/staged.git -b gh-pages
cd staged
cp -R $docs/* .
git add .
git commit --message "stage for review"
git push origin gh-pages
popd
----
The generated documentation is available from `target/site/reference/html/index.html`.
== Examples
* https://github.com/spring-projects/spring-data-examples/[Spring Data Examples] contains example projects that explain specific features in more detail.
== License
Spring Data Couchbase is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].

View File

@@ -0,0 +1,9 @@
# Security Policy
## Supported Versions
Please see the https://spring.io/projects/spring-data-couchbase[Spring Data Couchbase] project page for supported versions.
## Reporting a Vulnerability
Please don't raise security vulnerabilities here. Head over to https://pivotal.io/security to learn how to disclose them responsibly.

View File

@@ -0,0 +1,10 @@
{
"dependencies": {
"antora": "3.2.0-alpha.6",
"@antora/atlas-extension": "1.0.0-alpha.2",
"@antora/collector-extension": "1.0.0-alpha.7",
"@asciidoctor/tabs": "1.0.0-beta.6",
"@springio/antora-extensions": "1.13.0",
"@springio/asciidoctor-extensions": "1.0.0-alpha.11"
}
}

View File

@@ -0,0 +1,345 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>5.4.0-SNAPSHOT</version>
<name>Spring Data Couchbase</name>
<description>Spring Data integration for Couchbase</description>
<url>https://github.com/spring-projects/spring-data-couchbase</url>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase-parent</artifactId>
<version>5.4.0-SNAPSHOT</version>
</parent>
<properties>
<couchbase>3.7.4</couchbase>
<springdata.commons>3.4.0-SNAPSHOT</springdata.commons>
<java-module-name>spring.data.couchbase</java-module-name>
<hibernate.validator>7.0.1.Final</hibernate.validator>
<couchbase.encryption>3.1.0</couchbase.encryption>
<jodatime>2.10.13</jodatime>
<jackson-joda>2.13.4</jackson-joda>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${springdata.commons}</version>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
<version>${couchbase}</version>
</dependency>
<!-- CDI -->
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>${cdi}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.1.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${jackson-joda}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<!-- JSR 303 Validation -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>${validation}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId>
<version>${jakarta.el}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>${jakarta.el}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- CDI -->
<!-- Dependency order required to build against CDI 1.0 and test with CDI 2.0 -->
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jcdi_2.0_spec</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>1.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-se</artifactId>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.couchbase.mock</groupId>
<artifactId>CouchbaseMock</artifactId>
<version>1.5.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-tls</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<!-- Kotlin extension -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>couchbase-encryption</artifactId>
<version>${couchbase.encryption}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase-testutils</artifactId>
<version>0.0.99</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<proc>none</proc> <!-- don't try to run any AnnotationProcessor (especially any Querydsl annotation processor) -->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
<useFile>false</useFile>
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IntegrationTests.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<useModulePath>false</useModulePath>
<includes>
<include>**/*IntegrationTest.java</include>
<include>**/*IntegrationTests.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<legacyMode>true</legacyMode>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>antora-process-resources</id>
<build>
<resources>
<resource>
<directory>src/main/antora/resources/antora-resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</profile>
<profile>
<id>antora</id>
<build>
<plugins>
<plugin>
<groupId>org.antora</groupId>
<artifactId>antora-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>

View File

@@ -0,0 +1,29 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>spring-plugins-release</id>
<username>${env.ARTIFACTORY_USR}</username>
<password>${env.ARTIFACTORY_PSW}</password>
</server>
<server>
<id>spring-libs-snapshot</id>
<username>${env.ARTIFACTORY_USR}</username>
<password>${env.ARTIFACTORY_PSW}</password>
</server>
<server>
<id>spring-libs-milestone</id>
<username>${env.ARTIFACTORY_USR}</username>
<password>${env.ARTIFACTORY_PSW}</password>
</server>
<server>
<id>spring-libs-release</id>
<username>${env.ARTIFACTORY_USR}</username>
<password>${env.ARTIFACTORY_PSW}</password>
</server>
</servers>
</settings>

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