Addressing the remaining checkstyle failures

Signed-off-by: Soby Chacko <soby.chacko@broadcom.com>
This commit is contained in:
Soby Chacko
2025-04-14 16:53:06 -04:00
committed by Ilayaperumal Gopinathan
parent aaf1589669
commit 53a7af500b
87 changed files with 551 additions and 462 deletions

View File

@@ -175,22 +175,6 @@ public class McpClientAutoConfiguration {
return mcpSyncClients;
}
/**
* Record class that implements {@link AutoCloseable} to ensure proper cleanup of MCP
* clients.
*
* <p>
* This class is responsible for closing all MCP sync clients when the application
* context is closed, preventing resource leaks.
*/
public record CloseableMcpSyncClients(List<McpSyncClient> clients) implements AutoCloseable {
@Override
public void close() {
this.clients.forEach(McpSyncClient::close);
}
}
/**
* Creates a closeable wrapper for MCP sync clients to ensure proper resource cleanup.
* @param clients the list of MCP sync clients to manage
@@ -258,13 +242,6 @@ public class McpClientAutoConfiguration {
return mcpSyncClients;
}
public record CloseableMcpAsyncClients(List<McpAsyncClient> clients) implements AutoCloseable {
@Override
public void close() {
this.clients.forEach(McpAsyncClient::close);
}
}
@Bean
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
public CloseableMcpAsyncClients makeAsynClientsClosable(List<McpAsyncClient> clients) {
@@ -278,4 +255,27 @@ public class McpClientAutoConfiguration {
return new McpAsyncClientConfigurer(customizerProvider.orderedStream().toList());
}
/**
* Record class that implements {@link AutoCloseable} to ensure proper cleanup of MCP
* clients.
*
* <p>
* This class is responsible for closing all MCP sync clients when the application
* context is closed, preventing resource leaks.
*/
public record CloseableMcpSyncClients(List<McpSyncClient> clients) implements AutoCloseable {
@Override
public void close() {
this.clients.forEach(McpSyncClient::close);
}
}
public record CloseableMcpAsyncClients(List<McpAsyncClient> clients) implements AutoCloseable {
@Override
public void close() {
this.clients.forEach(McpAsyncClient::close);
}
}
}

View File

@@ -40,26 +40,6 @@ import org.springframework.context.annotation.Conditional;
@Conditional(McpToolCallbackAutoConfiguration.McpToolCallbackAutoconfigurationCondition.class)
public class McpToolCallbackAutoConfiguration {
public static class McpToolCallbackAutoconfigurationCondition extends AllNestedConditions {
public McpToolCallbackAutoconfigurationCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
matchIfMissing = true)
static class McpAutoConfigEnabled {
}
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX + ".toolcallback", name = "enabled",
havingValue = "true", matchIfMissing = false)
static class ToolCallbackProviderEnabled {
}
}
/**
* Creates tool callbacks for all configured MCP clients.
*
@@ -84,4 +64,24 @@ public class McpToolCallbackAutoConfiguration {
return new AsyncMcpToolCallbackProvider(mcpClients);
}
public static class McpToolCallbackAutoconfigurationCondition extends AllNestedConditions {
public McpToolCallbackAutoconfigurationCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
matchIfMissing = true)
static class McpAutoConfigEnabled {
}
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX + ".toolcallback", name = "enabled",
havingValue = "true", matchIfMissing = false)
static class ToolCallbackProviderEnabled {
}
}
}

View File

@@ -1,18 +1,19 @@
/*
* Copyright 2024 - 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.
*/
* Copyright 2025-2025 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.ai.mcp.client.autoconfigure;
import io.modelcontextprotocol.spec.McpClientTransport;

View File

@@ -26,10 +26,10 @@ import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.ai.mcp.client.autoconfigure.properties.McpClientCommonProperties;
import org.springframework.ai.mcp.client.autoconfigure.properties.McpSseClientProperties;
import org.springframework.ai.mcp.client.autoconfigure.properties.McpSseClientProperties.SseParameters;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;

View File

@@ -23,10 +23,10 @@ import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.ai.mcp.client.autoconfigure.properties.McpClientCommonProperties;
import org.springframework.ai.mcp.client.autoconfigure.properties.McpSseClientProperties;
import org.springframework.ai.mcp.client.autoconfigure.properties.McpSseClientProperties.SseParameters;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

View File

@@ -1,18 +1,19 @@
/*
* Copyright 2024 - 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.
*/
* Copyright 2025-2025 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.ai.mcp.client.autoconfigure.properties;
import java.util.HashMap;
@@ -46,14 +47,6 @@ public class McpSseClientProperties {
public static final String CONFIG_PREFIX = "spring.ai.mcp.client.sse";
/**
* Parameters for configuring an SSE connection to an MCP server.
*
* @param url the URL endpoint for SSE communication with the MCP server
*/
public record SseParameters(String url) {
}
/**
* Map of named SSE connection configurations.
* <p>
@@ -70,4 +63,12 @@ public class McpSseClientProperties {
return this.connections;
}
/**
* Parameters for configuring an SSE connection to an MCP server.
*
* @param url the URL endpoint for SSE communication with the MCP server
*/
public record SseParameters(String url) {
}
}

View File

@@ -73,32 +73,6 @@ public class McpStdioClientProperties {
return this.connections;
}
/**
* Record representing the parameters for an MCP server connection.
* <p>
* Includes the command to execute, command arguments, and environment variables.
*/
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record Parameters(
/**
* The command to execute for the MCP server.
*/
@JsonProperty("command") String command,
/**
* List of command arguments.
*/
@JsonProperty("args") List<String> args,
/**
* Map of environment variables for the server process.
*/
@JsonProperty("env") Map<String, String> env) {
public ServerParameters toServerParameters() {
return ServerParameters.builder(this.command()).args(this.args()).env(this.env()).build();
}
}
private Map<String, ServerParameters> resourceToServerParameters() {
try {
Map<String, Map<String, Parameters>> stdioConnection = new ObjectMapper().readValue(
@@ -133,4 +107,30 @@ public class McpStdioClientProperties {
return serverParameters;
}
/**
* Record representing the parameters for an MCP server connection.
* <p>
* Includes the command to execute, command arguments, and environment variables.
*/
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record Parameters(
/**
* The command to execute for the MCP server.
*/
@JsonProperty("command") String command,
/**
* List of command arguments.
*/
@JsonProperty("args") List<String> args,
/**
* Map of environment variables for the server process.
*/
@JsonProperty("env") Map<String, String> env) {
public ServerParameters toServerParameters() {
return ServerParameters.builder(this.command()).args(this.args()).env(this.env()).build();
}
}
}

View File

@@ -121,9 +121,9 @@ public class McpClientAutoConfigurationIT {
@Test
void closeableWrappersCreation() {
this.contextRunner.withUserConfiguration(TestTransportConfiguration.class).run(context -> {
assertThat(context).hasSingleBean(McpClientAutoConfiguration.CloseableMcpSyncClients.class);
});
this.contextRunner.withUserConfiguration(TestTransportConfiguration.class)
.run(context -> assertThat(context)
.hasSingleBean(McpClientAutoConfiguration.CloseableMcpSyncClients.class));
}
@Configuration

View File

@@ -31,21 +31,21 @@ public class McpToolCallbackAutoConfigurationTests {
@Test
void disabledByDeafault() {
this.applicationContext.run((context) -> {
this.applicationContext.run(context -> {
assertThat(context).doesNotHaveBean("mcpToolCallbacks");
assertThat(context).doesNotHaveBean("mcpAsyncToolCallbacks");
});
this.applicationContext
.withPropertyValues("spring.ai.mcp.client.enabled=true", "spring.ai.mcp.client.type=SYNC")
.run((context) -> {
.run(context -> {
assertThat(context).doesNotHaveBean("mcpToolCallbacks");
assertThat(context).doesNotHaveBean("mcpAsyncToolCallbacks");
});
this.applicationContext
.withPropertyValues("spring.ai.mcp.client.enabled=true", "spring.ai.mcp.client.type=ASYNC")
.run((context) -> {
.run(context -> {
assertThat(context).doesNotHaveBean("mcpToolCallbacks");
assertThat(context).doesNotHaveBean("mcpAsyncToolCallbacks");
});
@@ -55,7 +55,7 @@ public class McpToolCallbackAutoConfigurationTests {
void enabledMcpToolCallbackAutoconfiguration() {
// sync
this.applicationContext.withPropertyValues("spring.ai.mcp.client.toolcallback.enabled=true").run((context) -> {
this.applicationContext.withPropertyValues("spring.ai.mcp.client.toolcallback.enabled=true").run(context -> {
assertThat(context).hasBean("mcpToolCallbacks");
assertThat(context).doesNotHaveBean("mcpAsyncToolCallbacks");
});
@@ -63,7 +63,7 @@ public class McpToolCallbackAutoConfigurationTests {
this.applicationContext
.withPropertyValues("spring.ai.mcp.client.enabled=true", "spring.ai.mcp.client.toolcallback.enabled=true",
"spring.ai.mcp.client.type=SYNC")
.run((context) -> {
.run(context -> {
assertThat(context).hasBean("mcpToolCallbacks");
assertThat(context).doesNotHaveBean("mcpAsyncToolCallbacks");
});
@@ -71,7 +71,7 @@ public class McpToolCallbackAutoConfigurationTests {
// Async
this.applicationContext
.withPropertyValues("spring.ai.mcp.client.toolcallback.enabled=true", "spring.ai.mcp.client.type=ASYNC")
.run((context) -> {
.run(context -> {
assertThat(context).doesNotHaveBean("mcpToolCallbacks");
assertThat(context).hasBean("mcpAsyncToolCallbacks");
});
@@ -79,7 +79,7 @@ public class McpToolCallbackAutoConfigurationTests {
this.applicationContext
.withPropertyValues("spring.ai.mcp.client.enabled=true", "spring.ai.mcp.client.toolcallback.enabled=true",
"spring.ai.mcp.client.type=ASYNC")
.run((context) -> {
.run(context -> {
assertThat(context).doesNotHaveBean("mcpToolCallbacks");
assertThat(context).hasBean("mcpAsyncToolCallbacks");
});

View File

@@ -38,54 +38,43 @@ public class McpToolCallbackAutoconfigurationConditionTests {
void matchesWhenBothPropertiesAreEnabled() {
this.contextRunner
.withPropertyValues("spring.ai.mcp.client.enabled=true", "spring.ai.mcp.client.toolcallback.enabled=true")
.run(context -> {
assertThat(context).hasBean("testBean");
});
.run(context -> assertThat(context).hasBean("testBean"));
}
@Test
void doesNotMatchWhenMcpClientIsDisabled() {
this.contextRunner
.withPropertyValues("spring.ai.mcp.client.enabled=false", "spring.ai.mcp.client.toolcallback.enabled=true")
.run(context -> {
assertThat(context).doesNotHaveBean("testBean");
});
.run(context -> assertThat(context).doesNotHaveBean("testBean"));
}
@Test
void doesNotMatchWhenToolCallbackIsDisabled() {
this.contextRunner
.withPropertyValues("spring.ai.mcp.client.enabled=true", "spring.ai.mcp.client.toolcallback.enabled=false")
.run(context -> {
assertThat(context).doesNotHaveBean("testBean");
});
.run(context -> assertThat(context).doesNotHaveBean("testBean"));
}
@Test
void doesNotMatchWhenBothPropertiesAreDisabled() {
this.contextRunner
.withPropertyValues("spring.ai.mcp.client.enabled=false", "spring.ai.mcp.client.toolcallback.enabled=false")
.run(context -> {
assertThat(context).doesNotHaveBean("testBean");
});
.run(context -> assertThat(context).doesNotHaveBean("testBean"));
}
@Test
void doesNotMatchWhenToolCallbackPropertyIsMissing() {
// McpClientEnabled is true by default if missing, but ToolCallbackEnabled is
// false by default if missing
this.contextRunner.withPropertyValues("spring.ai.mcp.client.enabled=true").run(context -> {
assertThat(context).doesNotHaveBean("testBean");
});
this.contextRunner.withPropertyValues("spring.ai.mcp.client.enabled=true")
.run(context -> assertThat(context).doesNotHaveBean("testBean"));
}
@Test
void doesNotMatchWhenBothPropertiesAreMissing() {
// McpClientEnabled is true by default if missing, but ToolCallbackEnabled is
// false by default if missing
this.contextRunner.run(context -> {
assertThat(context).doesNotHaveBean("testBean");
});
this.contextRunner.run(context -> assertThat(context).doesNotHaveBean("testBean"));
}
@Configuration

View File

@@ -32,9 +32,7 @@ public class SseHttpClientTransportAutoConfigurationTests {
@Test
void mcpHttpClientTransportsNotPresentIfMissingWebFluxSseClientTransportPresent() {
this.applicationContext.run((context) -> {
assertThat(context.containsBean("mcpHttpClientTransports")).isFalse();
});
this.applicationContext.run(context -> assertThat(context.containsBean("mcpHttpClientTransports")).isFalse());
}
@Test
@@ -43,9 +41,7 @@ public class SseHttpClientTransportAutoConfigurationTests {
this.applicationContext
.withClassLoader(
new FilteredClassLoader("io.modelcontextprotocol.client.transport.WebFluxSseClientTransport"))
.run((context) -> {
assertThat(context.containsBean("mcpHttpClientTransports")).isTrue();
});
.run(context -> assertThat(context.containsBean("mcpHttpClientTransports")).isTrue());
}
@Test
@@ -55,9 +51,7 @@ public class SseHttpClientTransportAutoConfigurationTests {
.withClassLoader(
new FilteredClassLoader("io.modelcontextprotocol.client.transport.WebFluxSseClientTransport"))
.withPropertyValues("spring.ai.mcp.client.enabled", "false")
.run((context) -> {
assertThat(context.containsBean("mcpHttpClientTransports")).isFalse();
});
.run(context -> assertThat(context.containsBean("mcpHttpClientTransports")).isFalse());
}
}

View File

@@ -32,9 +32,7 @@ public class SseWebFluxTransportAutoConfigurationTests {
@Test
void webFluxClientTransportsPresentIfWebFluxSseClientTransportPresent() {
this.applicationContext.run((context) -> {
assertThat(context.containsBean("webFluxClientTransports")).isTrue();
});
this.applicationContext.run(context -> assertThat(context.containsBean("webFluxClientTransports")).isTrue());
}
@Test
@@ -43,17 +41,14 @@ public class SseWebFluxTransportAutoConfigurationTests {
this.applicationContext
.withClassLoader(
new FilteredClassLoader("io.modelcontextprotocol.client.transport.WebFluxSseClientTransport"))
.run((context) -> {
assertThat(context.containsBean("webFluxClientTransports")).isFalse();
});
.run(context -> assertThat(context.containsBean("webFluxClientTransports")).isFalse());
}
@Test
void webFluxClientTransportsNotPresentIfMcpClientDisabled() {
this.applicationContext.withPropertyValues("spring.ai.mcp.client.enabled", "false").run((context) -> {
assertThat(context.containsBean("webFluxClientTransports")).isFalse();
});
this.applicationContext.withPropertyValues("spring.ai.mcp.client.enabled", "false")
.run(context -> assertThat(context.containsBean("webFluxClientTransports")).isFalse());
}
}

View File

@@ -217,9 +217,7 @@ public class McpServerAutoConfiguration {
}
rootsChangeConsumers.ifAvailable(consumer -> {
serverBuilder.rootsChangeHandler((exchange, roots) -> {
consumer.accept(exchange, roots);
});
serverBuilder.rootsChangeHandler((exchange, roots) -> consumer.accept(exchange, roots));
logger.info("Registered roots change consumer");
});

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2025-2025 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.ai.mcp.server.autoconfigure;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -33,9 +49,8 @@ class McpWebFluxServerAutoConfigurationIT {
@Test
void stdioEnabledConfiguration() {
this.contextRunner.withPropertyValues("spring.ai.mcp.server.stdio=true").run(context -> {
assertThat(context).doesNotHaveBean(WebFluxSseServerTransportProvider.class);
});
this.contextRunner.withPropertyValues("spring.ai.mcp.server.stdio=true")
.run(context -> assertThat(context).doesNotHaveBean(WebFluxSseServerTransportProvider.class));
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2025-2025 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.ai.mcp.server.autoconfigure;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -33,9 +49,8 @@ class McpWebMvcServerAutoConfigurationTest {
@Test
void stdioEnabledConfiguration() {
this.contextRunner.withPropertyValues("spring.ai.mcp.server.stdio=true").run(context -> {
assertThat(context).doesNotHaveBean(WebMvcSseServerTransportProvider.class);
});
this.contextRunner.withPropertyValues("spring.ai.mcp.server.stdio=true")
.run(context -> assertThat(context).doesNotHaveBean(WebMvcSseServerTransportProvider.class));
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.ai.vectorstore.cosmosdb.autoconfigure;
import java.util.List;
import com.azure.cosmos.CosmosAsyncClient;
import com.azure.cosmos.CosmosClientBuilder;
import io.micrometer.observation.ObservationRegistry;
@@ -33,7 +35,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import java.util.List;
/**
* {@link AutoConfiguration Auto-configuration} for CosmosDB Vector Store.

View File

@@ -16,8 +16,8 @@
package org.springframework.ai.vectorstore.azure.autoconfigure;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.azure.AzureVectorStore;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**

View File

@@ -19,8 +19,8 @@ package org.springframework.ai.vectorstore.cassandra.autoconfigure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.cassandra.CassandraVectorStore;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.Assert;

View File

@@ -26,12 +26,12 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.cassandra.CassandraVectorStore;

View File

@@ -20,10 +20,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.chroma.vectorstore.ChromaApi;
import org.springframework.ai.chroma.vectorstore.ChromaVectorStore;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.chroma.vectorstore.ChromaVectorStore;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;

View File

@@ -16,8 +16,8 @@
package org.springframework.ai.vectorstore.chroma.autoconfigure;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.chroma.vectorstore.ChromaVectorStore;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2025 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore.couchbase.autoconfigure;
import com.couchbase.client.java.Cluster;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.CouchbaseSearchVectorStore;
import org.springframework.boot.autoconfigure.AutoConfiguration;

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2025 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore.couchbase.autoconfigure;
import org.springframework.ai.vectorstore.CouchbaseIndexOptimization;

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2025 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore.couchbase.autoconfigure;
import org.testcontainers.couchbase.BucketDefinition;
@@ -22,7 +23,7 @@ import org.testcontainers.utility.DockerImageName;
* @author Laurent Doguin
* @since 1.0.0
*/
public class CouchbaseContainerMetadata {
public final class CouchbaseContainerMetadata {
public static final String BUCKET_NAME = "example";
@@ -36,4 +37,8 @@ public class CouchbaseContainerMetadata {
.asCompatibleSubstituteFor("couchbase/server")
.withTag("enterprise-7.6.1");
private CouchbaseContainerMetadata() {
// Avoids instantiation
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2025 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,10 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore.couchbase.autoconfigure;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.couchbase.CouchbaseContainer;
import org.testcontainers.couchbase.CouchbaseService;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.document.Document;
import org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
@@ -28,21 +39,8 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.couchbase.CouchbaseContainer;
import org.testcontainers.couchbase.CouchbaseService;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.ai.vectorstore.couchbase.autoconfigure.CouchbaseContainerMetadata.COUCHBASE_IMAGE_ENTERPRISE;
import static org.springframework.ai.vectorstore.couchbase.autoconfigure.CouchbaseContainerMetadata.PASSWORD;
import static org.springframework.ai.vectorstore.couchbase.autoconfigure.CouchbaseContainerMetadata.USERNAME;
import static org.springframework.ai.vectorstore.couchbase.autoconfigure.CouchbaseContainerMetadata.bucketDefinition;
/**
* @author Laurent Doguin
@@ -54,11 +52,12 @@ class CouchbaseSearchVectorStoreAutoConfigurationIT {
// Define the couchbase container.
@Container
final static CouchbaseContainer couchbaseContainer = new CouchbaseContainer(COUCHBASE_IMAGE_ENTERPRISE)
.withCredentials(USERNAME, PASSWORD)
final static CouchbaseContainer couchbaseContainer = new CouchbaseContainer(
CouchbaseContainerMetadata.COUCHBASE_IMAGE_ENTERPRISE)
.withCredentials(CouchbaseContainerMetadata.USERNAME, CouchbaseContainerMetadata.PASSWORD)
.withEnabledServices(CouchbaseService.KV, CouchbaseService.QUERY, CouchbaseService.INDEX,
CouchbaseService.SEARCH)
.withBucket(bucketDefinition)
.withBucket(CouchbaseContainerMetadata.bucketDefinition)
.withStartupAttempts(4)
.withStartupTimeout(Duration.ofSeconds(90))
.waitingFor(Wait.forHealthcheck());

View File

@@ -16,8 +16,8 @@
package org.springframework.ai.vectorstore.elasticsearch.autoconfigure;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.elasticsearch.SimilarityFunction;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**

View File

@@ -29,14 +29,14 @@ import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
import org.springframework.ai.document.Document;
import org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.elasticsearch.ElasticsearchVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.elasticsearch.SimilarityFunction;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.boot.autoconfigure.AutoConfigurations;

View File

@@ -16,8 +16,8 @@
package org.springframework.ai.vectorstore.gemfire.autoconfigure;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.gemfire.GemFireVectorStore;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**

View File

@@ -33,15 +33,15 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.gemfire.GemFireVectorStore;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.gemfire.GemFireVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

View File

@@ -23,9 +23,9 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.document.Document;
import org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration;

View File

@@ -16,7 +16,10 @@
package org.springframework.ai.vectorstore.mariadb.autoconfigure;
import javax.sql.DataSource;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
@@ -33,8 +36,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
/**
* @author Diego Dupin
* @since 1.0.0

View File

@@ -16,9 +16,9 @@
package org.springframework.ai.vectorstore.mariadb.autoconfigure;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore;
import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore.MariaDBDistanceType;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**

View File

@@ -16,10 +16,20 @@
package org.springframework.ai.vectorstore.mariadb.autoconfigure;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import io.micrometer.observation.tck.TestObservationRegistry;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
@@ -37,15 +47,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.ai.test.vectorstore.ObservationTestUtil.assertObservationRegistry;
@@ -160,9 +161,7 @@ public class MariaDbStoreAutoConfigurationIT {
"spring.ai.vectorstore.mariadb.metadata-field-name=" + metaName,
"spring.ai.vectorstore.mariadb.embedding-field-name=" + embeddingName,
"spring.ai.vectorstore.mariadb.content-field-name=" + contentName)
.run(context -> {
assertThat(isFullyQualifiedTableExists(context, schemaName, tableName)).isTrue();
});
.run(context -> assertThat(isFullyQualifiedTableExists(context, schemaName, tableName)).isTrue());
}
@ParameterizedTest(name = "{0} : {displayName} ")
@@ -175,9 +174,7 @@ public class MariaDbStoreAutoConfigurationIT {
.withPropertyValues("spring.ai.vectorstore.mariadb.schema-name=" + schemaName,
"spring.ai.vectorstore.mariadb.table-name=" + tableName,
"spring.ai.vectorstore.mariadb.initialize-schema=false")
.run(context -> {
assertThat(isFullyQualifiedTableExists(context, schemaName, tableName)).isFalse();
});
.run(context -> assertThat(isFullyQualifiedTableExists(context, schemaName, tableName)).isFalse());
}
@Test

View File

@@ -21,9 +21,9 @@ import java.util.concurrent.TimeUnit;
import io.micrometer.observation.ObservationRegistry;
import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import io.milvus.param.IndexType;
import io.milvus.param.MetricType;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;

View File

@@ -16,8 +16,8 @@
package org.springframework.ai.vectorstore.milvus.autoconfigure;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.milvus.MilvusVectorStore;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.Assert;

View File

@@ -25,12 +25,12 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.milvus.MilvusContainer;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.milvus.MilvusVectorStore;

View File

@@ -27,10 +27,10 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.mongodb.MongoDBAtlasLocalContainer;
import org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
import org.springframework.ai.document.Document;
import org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;

View File

@@ -16,8 +16,8 @@
package org.springframework.ai.vectorstore.neo4j.autoconfigure;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.neo4j.Neo4jVectorStore;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**

View File

@@ -26,12 +26,12 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.neo4j.Neo4jVectorStore;

View File

@@ -41,8 +41,8 @@ import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

View File

@@ -32,12 +32,12 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;

View File

@@ -31,16 +31,16 @@ import org.testcontainers.utility.DockerImageName;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.regions.Region;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

View File

@@ -24,8 +24,8 @@ import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.oracle.OracleVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.ai.vectorstore.oracle.OracleVectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

View File

@@ -16,8 +16,8 @@
package org.springframework.ai.vectorstore.oracle.autoconfigure;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.oracle.OracleVectorStore;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**

View File

@@ -24,8 +24,8 @@ import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

View File

@@ -16,10 +16,10 @@
package org.springframework.ai.vectorstore.pgvector.autoconfigure;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgDistanceType;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType;
import org.springframework.ai.vectorstore.properties.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**

View File

@@ -34,10 +34,10 @@ import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;

View File

@@ -22,8 +22,8 @@ import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

View File

@@ -34,10 +34,10 @@ import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;

View File

@@ -26,8 +26,8 @@ import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;

View File

@@ -25,12 +25,12 @@ import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;

View File

@@ -29,8 +29,8 @@ import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.typesense.TypesenseVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.ai.vectorstore.typesense.TypesenseVectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

View File

@@ -25,12 +25,12 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.typesense.TypesenseContainer;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;

View File

@@ -33,7 +33,7 @@ import org.springframework.util.Assert;
*
* @author Alexandros Pappas
*/
public class JsoupDocumentReaderConfig {
public final class JsoupDocumentReaderConfig {
public final String charset;
@@ -70,7 +70,7 @@ public class JsoupDocumentReaderConfig {
return builder().build();
}
public static class Builder {
public static final class Builder {
private String charset = "UTF-8";

View File

@@ -18,7 +18,6 @@ package org.springframework.ai.reader.jsoup;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -28,6 +27,7 @@ import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.DefaultResourceLoader;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link JsoupDocumentReader}.

View File

@@ -112,7 +112,7 @@ public class PagePdfDocumentReader implements DocumentReader {
for (PDPage page : this.document.getDocumentCatalog().getPages()) {
lastPage = page;
if (counter % logFrequency == 0 && counter / logFrequency < 10) {
this.logger.info("Processing PDF page: {}", (counter + 1));
logger.info("Processing PDF page: {}", (counter + 1));
}
counter++;
@@ -154,7 +154,7 @@ public class PagePdfDocumentReader implements DocumentReader {
readDocuments.add(toDocument(lastPage, pageTextGroupList.stream().collect(Collectors.joining()),
startPageNumber, pageNumber));
}
this.logger.info("Processing {} pages", totalPages);
logger.info("Processing {} pages", totalPages);
return readDocuments;
}

View File

@@ -133,7 +133,7 @@ public class ParagraphPdfDocumentReader implements DocumentReader {
List<Document> documents = new ArrayList<>(paragraphs.size());
if (!CollectionUtils.isEmpty(paragraphs)) {
this.logger.info("Start processing paragraphs from PDF");
logger.info("Start processing paragraphs from PDF");
Iterator<Paragraph> itr = paragraphs.iterator();
var current = itr.next();
@@ -152,7 +152,7 @@ public class ParagraphPdfDocumentReader implements DocumentReader {
}
}
}
this.logger.info("End processing paragraphs from PDF");
logger.info("End processing paragraphs from PDF");
return documents;
}

View File

@@ -18,7 +18,9 @@ package org.springframework.ai.reader.tika;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.ai.reader.ExtractedTextFormatter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;

View File

@@ -360,8 +360,9 @@ public final class McpToolUtils {
}
@JsonIgnoreProperties(ignoreUnknown = true)
private record Base64Wrapper(@JsonAlias("mimetype") @Nullable MimeType mimeType, @JsonAlias( {
"base64", "b64", "imageData" }) @Nullable String data){
// @formatter:off
private record Base64Wrapper(@JsonAlias("mimetype") @Nullable MimeType mimeType, @JsonAlias({
"base64", "b64", "imageData" }) @Nullable String data) {
}
}

View File

@@ -288,7 +288,7 @@ public class MistralAiChatOptions implements ToolCallingChatOptions {
@Nullable
@JsonIgnore
public Boolean getInternalToolExecutionEnabled() {
return internalToolExecutionEnabled;
return this.internalToolExecutionEnabled;
}
@Override

View File

@@ -738,7 +738,7 @@ public class OllamaOptions implements ToolCallingChatOptions, EmbeddingOptions {
@JsonIgnore
public Boolean getInternalToolExecutionEnabled() {
return this.internalToolExecutionEnabled;
}
}
@Override
@JsonIgnore

View File

@@ -506,7 +506,7 @@ public class OpenAiChatOptions implements ToolCallingChatOptions {
@Nullable
@JsonIgnore
public Boolean getInternalToolExecutionEnabled() {
return internalToolExecutionEnabled;
return this.internalToolExecutionEnabled;
}
@Override

View File

@@ -26,7 +26,6 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.document.Document;
@@ -36,6 +35,7 @@ import org.springframework.ai.evaluation.EvaluationResponse;
import org.springframework.ai.evaluation.RelevancyEvaluator;
import org.springframework.ai.integration.tests.TestApplication;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.rag.preretrieval.query.expansion.MultiQueryExpander;
import org.springframework.ai.rag.preretrieval.query.transformation.CompressionQueryTransformer;
import org.springframework.ai.rag.preretrieval.query.transformation.RewriteQueryTransformer;

View File

@@ -18,6 +18,7 @@ package org.springframework.ai.integration.tests.rag.preretrieval.query.transfor
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.UserMessage;

View File

@@ -18,6 +18,7 @@ package org.springframework.ai.integration.tests.rag.preretrieval.query.transfor
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.integration.tests.TestApplication;
import org.springframework.ai.openai.OpenAiChatModel;

View File

@@ -29,8 +29,8 @@ import org.springframework.ai.integration.tests.TestApplication;
import org.springframework.ai.rag.Query;
import org.springframework.ai.rag.retrieval.search.DocumentRetriever;
import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.ai.vectorstore.filter.Filter;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

View File

@@ -76,9 +76,8 @@ public class FunctionToolCallbackTests {
.build()
.prompt()
.user("Welcome the users to the library")
.tools(FunctionToolCallback.builder("sayWelcome", (input) -> {
logger.info("CALLBACK - Welcoming users to the library");
})
.tools(FunctionToolCallback.builder("sayWelcome",
(Consumer<Object>) input -> logger.info("CALLBACK - Welcoming users to the library"))
.description("Welcome users to the library")
.inputType(Void.class)
.build())
@@ -105,9 +104,8 @@ public class FunctionToolCallbackTests {
.build()
.prompt()
.user("Welcome %s to the library".formatted("James Bond"))
.tools(FunctionToolCallback.builder("welcomeUser", (user) -> {
logger.info("CALLBACK - Welcoming {} to the library", ((User) user).name());
})
.tools(FunctionToolCallback.builder("welcomeUser",
(Consumer<Object>) user -> logger.info("CALLBACK - Welcoming {} to the library", ((User) user).name()))
.description("Welcome a specific user to the library")
.inputType(User.class)
.build())
@@ -202,7 +200,7 @@ public class FunctionToolCallbackTests {
@Bean(WELCOME)
@Description("Welcome users to the library")
Consumer<Void> welcome() {
return (input) -> logger.info("Welcoming users to the library");
return input -> logger.info("Welcoming users to the library");
}
@Bean(WELCOME_USER)
@@ -215,7 +213,7 @@ public class FunctionToolCallbackTests {
@Description("Get the list of books written by the given author available in the library")
Function<Author, List<Book>> booksByAuthor() {
return author -> {
logger.info("Getting books by author: "+ author.name());
logger.info("Getting books by author: " + author.name());
return this.bookService.getBooksByAuthor(author);
};
}

View File

@@ -22,7 +22,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.model.tool.ToolExecutionResult;
import reactor.core.publisher.Flux;
import org.springframework.ai.chat.messages.ToolResponseMessage;
@@ -36,6 +35,7 @@ import org.springframework.ai.integration.tests.tool.domain.Book;
import org.springframework.ai.integration.tests.tool.domain.BookService;
import org.springframework.ai.model.tool.ToolCallingChatOptions;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.model.tool.ToolExecutionResult;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.tool.ToolCallbacks;
import org.springframework.ai.tool.annotation.Tool;

View File

@@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class BookService {
private static final ConcurrentHashMap<Integer, Book> books = new ConcurrentHashMap<>(Map
.of( // @formatter:off
.of(// @formatter:off
1, new Book("His Dark Materials", "Philip Pullman"),
2, new Book("The Lion, the Witch and the Wardrobe", "C.S. Lewis"),
3, new Book("The Hobbit", "J.R.R. Tolkien"),

View File

@@ -16,9 +16,16 @@
package org.springframework.ai.integration.tests.vectorstore;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentMetadata;
import org.springframework.ai.integration.tests.TestApplication;
@@ -28,12 +35,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.DefaultResourceLoader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
/**

View File

@@ -24,13 +24,13 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.milvus.MilvusContainer;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;

View File

@@ -26,12 +26,12 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.qdrant.QdrantContainer;
import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;

View File

@@ -26,12 +26,12 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.qdrant.QdrantContainer;
import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;

View File

@@ -24,13 +24,13 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.typesense.TypesenseContainer;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.typesense.autoconfigure.TypesenseVectorStoreAutoConfiguration;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.util.ResourceUtils;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.typesense.autoconfigure.TypesenseVectorStoreAutoConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;

View File

@@ -25,14 +25,14 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.weaviate.WeaviateContainer;
import org.springframework.ai.vectorstore.weaviate.autoconfigure.WeaviateVectorStoreAutoConfiguration;
import org.springframework.ai.vectorstore.weaviate.autoconfigure.WeaviateVectorStoreProperties;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore;
import org.springframework.ai.vectorstore.weaviate.autoconfigure.WeaviateVectorStoreAutoConfiguration;
import org.springframework.ai.vectorstore.weaviate.autoconfigure.WeaviateVectorStoreProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;

View File

@@ -40,12 +40,14 @@
<suppress files="JsonParserTests.java" checks="RegexpSinglelineJava"/>
<suppress files="DockerModelRunnerWithOpenAiChatModelIT.java" checks="RegexpSinglelineJava"/>
<suppress files="AzureOpenAiChatModelMetadataTests.java" checks="RegexpSinglelineJava"/>
<suppress files="CouchbaseSearchVectorStore.java" checks="RegexpSinglelineJava"/>
<suppress files="OpenAiApi.java" checks="AnnotationLocation"/>
<suppress files="AzureVectorStore.java" checks="FinalClass"/>
<suppress files="CassandraVectorStore.java" checks="FinalClass"/>
<suppress files="CoherenceVectorStore.java" checks="FinalClass"/>
<suppress files="CosmosDBVectorStore.java" checks="FinalClass"/>
<suppress files="CouchbaseSearchVectorStore.java" checks="FinalClass"/>
<suppress files="GemFireVectorStore.java" checks="FinalClass"/>
<suppress files="MilvusVectorStore.java" checks="FinalClass"/>
<suppress files="HanaCloudVectorStore.java" checks="FinalClass"/>

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2024 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore;
import org.springframework.ai.vectorstore.filter.Filter.Expression;

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2024 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore;
/**

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2024 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,8 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import com.couchbase.client.core.util.ConsistencyUtil;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.Cluster;
@@ -29,6 +37,9 @@ import com.couchbase.client.java.query.QueryOptions;
import com.couchbase.client.java.query.QueryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import reactor.util.retry.RetrySpec;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.EmbeddingOptionsBuilder;
@@ -38,11 +49,6 @@ import org.springframework.ai.vectorstore.observation.AbstractObservationVectorS
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import reactor.core.publisher.Mono;
import reactor.util.retry.RetrySpec;
import java.time.Duration;
import java.util.*;
/**
* @author Laurent Doguin
@@ -203,141 +209,6 @@ public class CouchbaseSearchVectorStore extends AbstractObservationVectorStore
return new Builder(cluster, embeddingModel);
}
public static class Builder extends AbstractVectorStoreBuilder<Builder> {
private String collectionName = DEFAULT_COLLECTION_NAME;
private String scopeName = DEFAULT_SCOPE_NAME;
private String bucketName = DEFAULT_BUCKET_NAME;
private String vectorIndexName = DEFAULT_INDEX_NAME;
private Integer dimensions = 1536;
private CouchbaseSimilarityFunction similarityFunction = CouchbaseSimilarityFunction.dot_product;
private CouchbaseIndexOptimization indexOptimization = CouchbaseIndexOptimization.recall;
private final Cluster cluster;
private final CouchbaseAiSearchFilterExpressionConverter filterExpressionConverter = new CouchbaseAiSearchFilterExpressionConverter();
private boolean initializeSchema = false;
/**
* @throws IllegalArgumentException if couchbaseSearchVectorConfig or cluster is
* null
*/
private Builder(Cluster cluster, EmbeddingModel embeddingModel) {
super(embeddingModel);
Assert.notNull(cluster, "Cluster must not be null");
this.cluster = cluster;
}
/**
* Sets whether to initialize the schema.
* @param initializeSchema true to initialize schema, false otherwise
* @return the builder instance
*/
public Builder initializeSchema(boolean initializeSchema) {
this.initializeSchema = initializeSchema;
return this;
}
/**
* Configures the Couchbase collection storing {@link Document}.
* @param collectionName
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder collectionName(String collectionName) {
Assert.notNull(collectionName, "Collection Name must not be null");
Assert.notNull(collectionName, "Collection Name must not be empty");
this.collectionName = collectionName;
return this;
}
/**
* Configures the Couchbase scope, parent of the selected collection. Search will
* be executed in this scope context.
* @param scopeName
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder scopeName(String scopeName) {
Assert.notNull(scopeName, "Scope Name must not be null");
Assert.notNull(scopeName, "Scope Name must not be empty");
this.scopeName = scopeName;
return this;
}
/**
* Configures the Couchbase bucket, parent of the selected Scope.
* @param bucketName
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder bucketName(String bucketName) {
Assert.notNull(bucketName, "Bucket Name must not be null");
Assert.notNull(bucketName, "Bucket Name must not be empty");
this.bucketName = bucketName;
return this;
}
/**
* Configures the vector index name. This must match the name of the Vector Search
* Index Name in Atlas
* @param vectorIndexName
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder vectorIndexName(String vectorIndexName) {
Assert.notNull(vectorIndexName, "Vector Index Name must not be null");
Assert.notNull(vectorIndexName, "Vector Index Name must not be empty");
this.vectorIndexName = vectorIndexName;
return this;
}
/**
* The number of dimensions in the vector.
* @param dimensions
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder dimensions(Integer dimensions) {
Assert.notNull(dimensions, "Dimensions must not be null");
Assert.notNull(dimensions, "Dimensions must not be empty");
this.dimensions = dimensions;
return this;
}
/**
* Choose the method to calculate the similarity between the vector embedding in a
* Vector Search index and the vector embedding in a Vector Search query.
* @param similarityFunction
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder similarityFunction(CouchbaseSimilarityFunction similarityFunction) {
Assert.notNull(similarityFunction, "Couchbase Similarity Function must not be null");
Assert.notNull(similarityFunction, "Couchbase Similarity Function must not be empty");
this.similarityFunction = similarityFunction;
return this;
}
/**
* Choose to prioritize accuracy or latency.
* @param indexOptimization
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder indexOptimization(CouchbaseIndexOptimization indexOptimization) {
Assert.notNull(indexOptimization, "Index Optimization must not be null");
Assert.notNull(indexOptimization, "Index Optimization must not be empty");
this.indexOptimization = indexOptimization;
return this;
}
public CouchbaseSearchVectorStore build() {
return new CouchbaseSearchVectorStore(this);
}
}
public void initCluster() throws InterruptedException {
// init scope, collection, indexes
BucketSettings bs = this.cluster.buckets().getAllBuckets().get(this.bucketName);
@@ -478,4 +349,139 @@ public class CouchbaseSearchVectorStore extends AbstractObservationVectorStore
public record CouchbaseDocument(String id, String content, Map<String, Object> metadata, float[] embedding) {
}
public static class Builder extends AbstractVectorStoreBuilder<Builder> {
private String collectionName = DEFAULT_COLLECTION_NAME;
private String scopeName = DEFAULT_SCOPE_NAME;
private String bucketName = DEFAULT_BUCKET_NAME;
private String vectorIndexName = DEFAULT_INDEX_NAME;
private Integer dimensions = 1536;
private CouchbaseSimilarityFunction similarityFunction = CouchbaseSimilarityFunction.dot_product;
private CouchbaseIndexOptimization indexOptimization = CouchbaseIndexOptimization.recall;
private final Cluster cluster;
private final CouchbaseAiSearchFilterExpressionConverter filterExpressionConverter = new CouchbaseAiSearchFilterExpressionConverter();
private boolean initializeSchema = false;
/**
* @throws IllegalArgumentException if couchbaseSearchVectorConfig or cluster is
* null
*/
private Builder(Cluster cluster, EmbeddingModel embeddingModel) {
super(embeddingModel);
Assert.notNull(cluster, "Cluster must not be null");
this.cluster = cluster;
}
/**
* Sets whether to initialize the schema.
* @param initializeSchema true to initialize schema, false otherwise
* @return the builder instance
*/
public Builder initializeSchema(boolean initializeSchema) {
this.initializeSchema = initializeSchema;
return this;
}
/**
* Configures the Couchbase collection storing {@link Document}.
* @param collectionName
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder collectionName(String collectionName) {
Assert.notNull(collectionName, "Collection Name must not be null");
Assert.notNull(collectionName, "Collection Name must not be empty");
this.collectionName = collectionName;
return this;
}
/**
* Configures the Couchbase scope, parent of the selected collection. Search will
* be executed in this scope context.
* @param scopeName
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder scopeName(String scopeName) {
Assert.notNull(scopeName, "Scope Name must not be null");
Assert.notNull(scopeName, "Scope Name must not be empty");
this.scopeName = scopeName;
return this;
}
/**
* Configures the Couchbase bucket, parent of the selected Scope.
* @param bucketName
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder bucketName(String bucketName) {
Assert.notNull(bucketName, "Bucket Name must not be null");
Assert.notNull(bucketName, "Bucket Name must not be empty");
this.bucketName = bucketName;
return this;
}
/**
* Configures the vector index name. This must match the name of the Vector Search
* Index Name in Atlas
* @param vectorIndexName
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder vectorIndexName(String vectorIndexName) {
Assert.notNull(vectorIndexName, "Vector Index Name must not be null");
Assert.notNull(vectorIndexName, "Vector Index Name must not be empty");
this.vectorIndexName = vectorIndexName;
return this;
}
/**
* The number of dimensions in the vector.
* @param dimensions
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder dimensions(Integer dimensions) {
Assert.notNull(dimensions, "Dimensions must not be null");
Assert.notNull(dimensions, "Dimensions must not be empty");
this.dimensions = dimensions;
return this;
}
/**
* Choose the method to calculate the similarity between the vector embedding in a
* Vector Search index and the vector embedding in a Vector Search query.
* @param similarityFunction
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder similarityFunction(CouchbaseSimilarityFunction similarityFunction) {
Assert.notNull(similarityFunction, "Couchbase Similarity Function must not be null");
Assert.notNull(similarityFunction, "Couchbase Similarity Function must not be empty");
this.similarityFunction = similarityFunction;
return this;
}
/**
* Choose to prioritize accuracy or latency.
* @param indexOptimization
* @return this builder
*/
public CouchbaseSearchVectorStore.Builder indexOptimization(CouchbaseIndexOptimization indexOptimization) {
Assert.notNull(indexOptimization, "Index Optimization must not be null");
Assert.notNull(indexOptimization, "Index Optimization must not be empty");
this.indexOptimization = indexOptimization;
return this;
}
public CouchbaseSearchVectorStore build() {
return new CouchbaseSearchVectorStore(this);
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2024 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore;
/**

View File

@@ -1 +0,0 @@
spring.application.name=demo

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2024 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,37 +13,43 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.couchbase.client.java.Cluster;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.vectorstore.filter.Filter;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.couchbase.CouchbaseContainer;
import org.testcontainers.couchbase.CouchbaseService;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.vectorstore.filter.Filter;
import org.springframework.ai.vectorstore.testcontainer.CouchbaseContainerMetadata;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.ai.vectorstore.testcontainer.CouchbaseContainerMetadata.*;
/**
* @author Laurent Doguin
@@ -55,11 +61,12 @@ public class CouchbaseSearchVectorStoreIT {
// Define the couchbase container.
@Container
final static CouchbaseContainer couchbaseContainer = new CouchbaseContainer(COUCHBASE_IMAGE_ENTERPRISE)
.withCredentials(USERNAME, PASSWORD)
final static CouchbaseContainer couchbaseContainer = new CouchbaseContainer(
CouchbaseContainerMetadata.COUCHBASE_IMAGE_ENTERPRISE)
.withCredentials(CouchbaseContainerMetadata.USERNAME, CouchbaseContainerMetadata.PASSWORD)
.withEnabledServices(CouchbaseService.KV, CouchbaseService.QUERY, CouchbaseService.INDEX,
CouchbaseService.SEARCH)
.withBucket(bucketDefinition)
.withBucket(CouchbaseContainerMetadata.bucketDefinition)
.withStartupAttempts(4)
.withStartupTimeout(Duration.ofSeconds(90))
.waitingFor(Wait.forHealthcheck());

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2023 - 2024 the original author or authors.
* Copyright 2025-2025 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
* 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,
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore.testcontainer;
import org.testcontainers.couchbase.BucketDefinition;
@@ -22,7 +23,7 @@ import org.testcontainers.utility.DockerImageName;
* @author Laurent Doguin
* @since 1.0.0
*/
public class CouchbaseContainerMetadata {
public final class CouchbaseContainerMetadata {
public static final String BUCKET_NAME = "springBucket";
@@ -36,4 +37,8 @@ public class CouchbaseContainerMetadata {
.asCompatibleSubstituteFor("couchbase/server")
.withTag("enterprise-7.6.1");
private CouchbaseContainerMetadata() {
// Avoids instantiation
}
}

View File

@@ -1 +1 @@
spring.application.name=demo
spring.application.name=demo

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2025-2025 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.ai.vectorstore.milvus;
import org.springframework.ai.vectorstore.SearchRequest;

View File

@@ -1,10 +1,26 @@
/*
* Copyright 2023-2025 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.ai.vectorstore.milvus;
import org.junit.jupiter.api.Test;
import org.springframework.ai.vectorstore.SearchRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.ai.vectorstore.SearchRequest.DEFAULT_TOP_K;
import static org.springframework.ai.vectorstore.SearchRequest.SIMILARITY_THRESHOLD_ACCEPT_ALL;
/**
* Test class for verifying the functionality of the {@link MilvusSearchRequest} class.
@@ -41,8 +57,8 @@ class MilvusSearchRequestTest {
MilvusSearchRequest request = MilvusSearchRequest.milvusBuilder().build();
assertThat(request.getQuery()).isEmpty();
assertThat(request.getTopK()).isEqualTo(DEFAULT_TOP_K);
assertThat(request.getSimilarityThreshold()).isEqualTo(SIMILARITY_THRESHOLD_ACCEPT_ALL);
assertThat(request.getTopK()).isEqualTo(SearchRequest.DEFAULT_TOP_K);
assertThat(request.getSimilarityThreshold()).isEqualTo(SearchRequest.SIMILARITY_THRESHOLD_ACCEPT_ALL);
assertThat(request.getNativeExpression()).isNull();
assertThat(request.getSearchParamsJson()).isNull();
}

View File

@@ -1,5 +1,23 @@
/*
* Copyright 2025-2025 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.ai.vectorstore.milvus;
import java.util.List;
import io.milvus.client.MilvusServiceClient;
import io.milvus.grpc.SearchResultData;
import io.milvus.grpc.SearchResults;
@@ -14,13 +32,12 @@ import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.model.EmbeddingUtils;
import org.springframework.ai.vectorstore.SearchRequest;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;