From 69d5b5fcf05cff1f319536afac3c2991b521e8d9 Mon Sep 17 00:00:00 2001 From: Mark Pollack Date: Thu, 27 Mar 2025 17:58:06 -0400 Subject: [PATCH] Extract core modules for improved architecture Extract functionality from spring-ai-core into dedicated modules: - spring-ai-commons: Common utilities and document handling - spring-ai-model: Core model interfaces and implementations - spring-ai-vector-store: Vector store abstraction and implementation This modularization creates clearer responsibility boundaries and allows consumers to include only what they need. The restructuring will make the codebase easier to maintain and extend as the project grows. --- pom.xml | 3 + spring-ai-commons/pom.xml | 108 + .../ai/document/ContentFormatter.java | 0 .../ai/document/DefaultContentFormatter.java | 0 .../springframework/ai/document/Document.java | 0 .../ai/document/DocumentMetadata.java | 4 +- .../ai/document/DocumentReader.java | 0 .../ai/document/DocumentTransformer.java | 0 .../ai/document/DocumentWriter.java | 0 .../ai/document/MetadataMode.java | 0 .../ai/document/id/IdGenerator.java | 0 .../document/id/JdkSha256HexIdGenerator.java | 0 .../ai/document/id/RandomIdGenerator.java | 0 .../ai/document/package-info.java | 0 .../ai/embedding/BatchingStrategy.java | 2 +- .../embedding/TokenCountBatchingStrategy.java | 2 +- .../org/springframework/ai/model/Content.java | 2 +- .../org/springframework/ai/model/Media.java | 0 .../ai/model/MediaContent.java | 2 +- .../ai/observation/AiOperationMetadata.java | 0 .../conventions/AiObservationAttributes.java | 2 +- .../conventions/AiObservationEventNames.java | 2 +- .../AiObservationMetricAttributes.java | 2 +- .../conventions/AiObservationMetricNames.java | 2 +- .../conventions/AiOperationType.java | 2 +- .../observation/conventions/AiProvider.java | 2 +- .../observation/conventions/AiTokenType.java | 2 +- .../observation/conventions/SpringAiKind.java | 2 +- .../VectorStoreObservationAttributes.java | 2 +- .../VectorStoreObservationEventNames.java | 2 +- .../conventions/VectorStoreProvider.java | 2 +- .../VectorStoreSimilarityMetric.java | 2 +- .../observation/conventions/package-info.java | 2 +- .../ai/observation/package-info.java | 9 +- .../ai/observation/tracing/TracingHelper.java | 2 +- .../tokenizer/JTokkitTokenCountEstimator.java | 2 +- .../ai/tokenizer/TokenCountEstimator.java | 2 +- .../springframework/ai/util/JacksonUtils.java | 2 +- .../ai/document/ContentFormatterTests.java | 0 .../ai/document/DocumentBuilderTests.java | 0 .../ai/document/DocumentTests.java | 0 .../document/id/IdGeneratorProviderTest.java | 0 .../id/JdkSha256HexIdGeneratorTest.java | 0 .../TokenCountBatchingStrategyTests.java | 2 +- .../observation/AiOperationMetadataTests.java | 2 +- .../tracing/TracingHelperTests.java | 2 +- .../ai/utils/JacksonUtilsKotlinTests.kt | 2 +- .../src/test/resources/text_source.txt | 4124 +++++++++++++++++ spring-ai-core/pom.xml | 48 +- spring-ai-model/pom.xml | 128 + .../ai/chat/metadata/DefaultUsage.java | 2 +- .../ai/chat/metadata/EmptyUsage.java | 2 +- .../ai/chat/metadata/Usage.java | 2 +- .../ai/embedding/AbstractEmbeddingModel.java | 0 .../ai/embedding/DocumentEmbeddingModel.java | 0 .../embedding/DocumentEmbeddingRequest.java | 0 .../ai/embedding/Embedding.java | 0 .../ai/embedding/EmbeddingModel.java | 0 .../ai/embedding/EmbeddingOptions.java | 0 .../ai/embedding/EmbeddingOptionsBuilder.java | 0 .../ai/embedding/EmbeddingRequest.java | 0 .../ai/embedding/EmbeddingResponse.java | 0 .../embedding/EmbeddingResponseMetadata.java | 0 .../ai/embedding/EmbeddingResultMetadata.java | 0 ...ltEmbeddingModelObservationConvention.java | 0 ...EmbeddingModelMeterObservationHandler.java | 0 .../EmbeddingModelObservationContext.java | 0 .../EmbeddingModelObservationConvention.java | 0 ...mbeddingModelObservationDocumentation.java | 0 .../embedding/observation/package-info.java | 0 .../ai/embedding/package-info.java | 0 .../ai/model/AbstractResponseMetadata.java | 0 .../org/springframework/ai/model/ApiKey.java | 0 .../ai/model/ChatModelDescription.java | 0 .../ai/model/EmbeddingModelDescription.java | 0 .../ai/model/EmbeddingUtils.java | 0 .../ai/model/KotlinModule.java | 0 .../org/springframework/ai/model/Model.java | 0 .../ai/model/ModelDescription.java | 0 .../ai/model/ModelOptions.java | 0 .../ai/model/ModelOptionsUtils.java | 0 .../ai/model/ModelRequest.java | 0 .../ai/model/ModelResponse.java | 0 .../springframework/ai/model/ModelResult.java | 0 .../ai/model/MutableResponseMetadata.java | 0 .../springframework/ai/model/NoopApiKey.java | 0 .../ai/model/ResponseMetadata.java | 0 .../ai/model/ResultMetadata.java | 0 .../ai/model/SimpleApiKey.java | 0 .../ai/model/SpringAIModelProperties.java | 0 .../ai/model/SpringAIModels.java | 0 .../ai/model/StreamingModel.java | 0 .../ErrorLoggingObservationHandler.java | 0 .../observation/ModelObservationContext.java | 0 .../ModelUsageMetricsGenerator.java | 0 .../ai/model/observation/package-info.java | 0 .../ai/model/package-info.java | 28 + .../embedding-model-dimensions.properties | 0 .../ai/chat/metadata/DefaultUsageTests.java | 2 +- .../AbstractEmbeddingModelTests.java | 0 ...eddingModelObservationConventionTests.java | 0 ...dingModelMeterObservationHandlerTests.java | 0 ...EmbeddingModelObservationContextTests.java | 0 .../ai/metadata/UsageTests.java | 2 +- .../springframework/ai/model/MediaTests.java | 0 .../ai/model/ModelOptionsUtilsTests.java | 0 .../ModelObservationContextTests.java | 0 .../ModelUsageMetricsGeneratorTests.java | 0 spring-ai-vector-store/pom.xml | 122 + .../AbstractVectorStoreBuilder.java | 0 .../ai/vectorstore/SearchRequest.java | 0 .../ai/vectorstore/SimpleVectorStore.java | 0 .../vectorstore/SimpleVectorStoreContent.java | 0 .../vectorstore/SpringAIVectorStoreTypes.java | 0 .../ai/vectorstore/VectorStore.java | 0 .../ai/vectorstore/filter/Filter.java | 0 .../filter/FilterExpressionBuilder.java | 0 .../filter/FilterExpressionConverter.java | 0 .../filter/FilterExpressionTextParser.java | 0 .../ai/vectorstore/filter/FilterHelper.java | 0 .../vectorstore/filter/antlr4/Filters.interp | 0 .../filter/antlr4/FiltersBaseListener.java | 0 .../filter/antlr4/FiltersBaseVisitor.java | 0 .../filter/antlr4/FiltersLexer.interp | 0 .../filter/antlr4/FiltersLexer.java | 0 .../filter/antlr4/FiltersListener.java | 0 .../filter/antlr4/FiltersParser.java | 0 .../filter/antlr4/FiltersVisitor.java | 0 .../AbstractFilterExpressionConverter.java | 0 .../PineconeFilterExpressionConverter.java | 0 .../PrintFilterExpressionConverter.java | 0 ...eVectorStoreFilterExpressionConverter.java | 0 .../AbstractObservationVectorStore.java | 0 ...faultVectorStoreObservationConvention.java | 0 ...ectorStoreObservationContentProcessor.java | 0 .../VectorStoreObservationContext.java | 0 .../VectorStoreObservationConvention.java | 0 .../VectorStoreObservationDocumentation.java | 0 ...orStoreQueryResponseObservationFilter.java | 0 ...rStoreQueryResponseObservationHandler.java | 0 .../vectorstore/observation/package-info.java | 0 .../ai/vectorstore/package-info.java | 0 .../CommonVectorStoreProperties.java | 0 .../ai/vectorstore/filter/antlr4/Filters.g4 | 0 .../SimpleVectorStoreSimilarityTests.java | 2 +- .../vectorstore/SimpleVectorStoreTests.java | 0 .../SimpleVectorStoreWithFilterTests.java | 0 .../filter/FilterExpressionBuilderTests.java | 0 .../FilterExpressionTextParserTests.java | 0 .../vectorstore/filter/FilterHelperTests.java | 0 .../filter/SearchRequestTests.java | 0 ...ineconeFilterExpressionConverterTests.java | 0 ...orStoreFilterExpressionConverterTests.java | 0 ...VectorStoreObservationConventionTests.java | 0 .../VectorStoreObservationContextTests.java | 0 ...reQueryResponseObservationFilterTests.java | 0 ...eQueryResponseObservationHandlerTests.java | 0 src/checkstyle/checkstyle.xml | 2 +- 158 files changed, 4567 insertions(+), 71 deletions(-) create mode 100644 spring-ai-commons/pom.xml rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/ContentFormatter.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/DefaultContentFormatter.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/Document.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/DocumentMetadata.java (94%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/DocumentReader.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/DocumentTransformer.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/DocumentWriter.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/MetadataMode.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/id/IdGenerator.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/id/JdkSha256HexIdGenerator.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/id/RandomIdGenerator.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/document/package-info.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/embedding/BatchingStrategy.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/embedding/TokenCountBatchingStrategy.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/model/Content.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/model/Media.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/model/MediaContent.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/AiOperationMetadata.java (100%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/AiObservationAttributes.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/AiObservationEventNames.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricAttributes.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricNames.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/AiOperationType.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/AiProvider.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/AiTokenType.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/SpringAiKind.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationEventNames.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/VectorStoreSimilarityMetric.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/conventions/package-info.java (94%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/package-info.java (74%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/observation/tracing/TracingHelper.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/tokenizer/JTokkitTokenCountEstimator.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/tokenizer/TokenCountEstimator.java (99%) rename {spring-ai-core => spring-ai-commons}/src/main/java/org/springframework/ai/util/JacksonUtils.java (99%) rename {spring-ai-core => spring-ai-commons}/src/test/java/org/springframework/ai/document/ContentFormatterTests.java (100%) rename {spring-ai-core => spring-ai-commons}/src/test/java/org/springframework/ai/document/DocumentBuilderTests.java (100%) rename {spring-ai-core => spring-ai-commons}/src/test/java/org/springframework/ai/document/DocumentTests.java (100%) rename {spring-ai-core => spring-ai-commons}/src/test/java/org/springframework/ai/document/id/IdGeneratorProviderTest.java (100%) rename {spring-ai-core => spring-ai-commons}/src/test/java/org/springframework/ai/document/id/JdkSha256HexIdGeneratorTest.java (100%) rename {spring-ai-core => spring-ai-commons}/src/test/java/org/springframework/ai/embedding/TokenCountBatchingStrategyTests.java (99%) rename {spring-ai-core => spring-ai-commons}/src/test/java/org/springframework/ai/observation/AiOperationMetadataTests.java (99%) rename {spring-ai-core => spring-ai-commons}/src/test/java/org/springframework/ai/observation/tracing/TracingHelperTests.java (99%) rename {spring-ai-core => spring-ai-commons}/src/test/kotlin/org/springframework/ai/utils/JacksonUtilsKotlinTests.kt (99%) create mode 100644 spring-ai-commons/src/test/resources/text_source.txt create mode 100644 spring-ai-model/pom.xml rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/chat/metadata/DefaultUsage.java (99%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/chat/metadata/EmptyUsage.java (99%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/chat/metadata/Usage.java (99%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/AbstractEmbeddingModel.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingModel.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingRequest.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/Embedding.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/EmbeddingModel.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/EmbeddingOptions.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/EmbeddingOptionsBuilder.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/EmbeddingRequest.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/EmbeddingResponse.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/EmbeddingResponseMetadata.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/EmbeddingResultMetadata.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConvention.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandler.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContext.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationConvention.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationDocumentation.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/observation/package-info.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/embedding/package-info.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/AbstractResponseMetadata.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ApiKey.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ChatModelDescription.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/EmbeddingModelDescription.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/EmbeddingUtils.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/KotlinModule.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/Model.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ModelDescription.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ModelOptions.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ModelOptionsUtils.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ModelRequest.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ModelResponse.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ModelResult.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/MutableResponseMetadata.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/NoopApiKey.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ResponseMetadata.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/ResultMetadata.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/SimpleApiKey.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/SpringAIModelProperties.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/SpringAIModels.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/StreamingModel.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/observation/ErrorLoggingObservationHandler.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/observation/ModelObservationContext.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/observation/ModelUsageMetricsGenerator.java (100%) rename {spring-ai-core => spring-ai-model}/src/main/java/org/springframework/ai/model/observation/package-info.java (100%) create mode 100644 spring-ai-model/src/main/java/org/springframework/ai/model/package-info.java rename {spring-ai-core => spring-ai-model}/src/main/resources/embedding/embedding-model-dimensions.properties (100%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/chat/metadata/DefaultUsageTests.java (99%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/embedding/AbstractEmbeddingModelTests.java (100%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConventionTests.java (100%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandlerTests.java (100%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContextTests.java (100%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/metadata/UsageTests.java (99%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/model/MediaTests.java (100%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/model/ModelOptionsUtilsTests.java (100%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/model/observation/ModelObservationContextTests.java (100%) rename {spring-ai-core => spring-ai-model}/src/test/java/org/springframework/ai/model/observation/ModelUsageMetricsGeneratorTests.java (100%) create mode 100644 spring-ai-vector-store/pom.xml rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/AbstractVectorStoreBuilder.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/SearchRequest.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStore.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreContent.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/SpringAIVectorStoreTypes.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/VectorStore.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/Filter.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilder.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionConverter.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParser.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/FilterHelper.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/Filters.interp (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseListener.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseVisitor.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.interp (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersListener.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersParser.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersVisitor.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/converter/AbstractFilterExpressionConverter.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverter.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/converter/PrintFilterExpressionConverter.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverter.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConvention.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContentProcessor.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContext.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationConvention.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationDocumentation.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilter.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandler.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/observation/package-info.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/package-info.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/java/org/springframework/ai/vectorstore/properties/CommonVectorStoreProperties.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/main/resources/antlr4/org/springframework/ai/vectorstore/filter/antlr4/Filters.g4 (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreSimilarityTests.java (97%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreWithFilterTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilderTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParserTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/filter/FilterHelperTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/filter/SearchRequestTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverterTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverterTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContextTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilterTests.java (100%) rename {spring-ai-core => spring-ai-vector-store}/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandlerTests.java (100%) diff --git a/pom.xml b/pom.xml index 8dfc01c0d..794633983 100644 --- a/pom.xml +++ b/pom.xml @@ -32,8 +32,11 @@ spring-ai-docs spring-ai-bom + spring-ai-commons spring-ai-core + spring-ai-model spring-ai-test + spring-ai-vector-store auto-configurations/common/spring-ai-autoconfigure-retry diff --git a/spring-ai-commons/pom.xml b/spring-ai-commons/pom.xml new file mode 100644 index 000000000..1461a34ad --- /dev/null +++ b/spring-ai-commons/pom.xml @@ -0,0 +1,108 @@ + + + + + 4.0.0 + + org.springframework.ai + spring-ai + 1.0.0-SNAPSHOT + + spring-ai-commons + jar + Spring AI Commons + Common classes used across Spring AI + https://github.com/spring-projects/spring-ai + + + https://github.com/spring-projects/spring-ai + git://github.com/spring-projects/spring-ai.git + git@github.com:spring-projects/spring-ai.git + + + + + + org.springframework + spring-context + + + + io.micrometer + micrometer-core + + + + io.micrometer + context-propagation + + + + io.micrometer + micrometer-tracing-bridge-otel + true + + + + + com.fasterxml.jackson.module + jackson-module-jsonSchema + + + + com.fasterxml.jackson.core + jackson-databind + + + + org.jetbrains.kotlin + kotlin-stdlib + true + + + + org.jetbrains.kotlin + kotlin-reflect + true + + + + + com.knuddels + jtokkit + ${jtokkit.version} + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.fasterxml.jackson.module + jackson-module-kotlin + test + + + + + + diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/ContentFormatter.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/ContentFormatter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/ContentFormatter.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/ContentFormatter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/DefaultContentFormatter.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/DefaultContentFormatter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/DefaultContentFormatter.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/DefaultContentFormatter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/Document.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/Document.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/Document.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/Document.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/DocumentMetadata.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/DocumentMetadata.java similarity index 94% rename from spring-ai-core/src/main/java/org/springframework/ai/document/DocumentMetadata.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/DocumentMetadata.java index 3c0fb6010..d5a5435e1 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/document/DocumentMetadata.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/document/DocumentMetadata.java @@ -16,11 +16,9 @@ package org.springframework.ai.document; -import org.springframework.ai.vectorstore.VectorStore; - /** * Common set of metadata keys used in {@link Document}s by {@link DocumentReader}s and - * {@link VectorStore}s. + * VectorStores. * * @author Thomas Vitale * @since 1.0.0 diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/DocumentReader.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/DocumentReader.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/DocumentReader.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/DocumentReader.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/DocumentTransformer.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/DocumentTransformer.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/DocumentTransformer.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/DocumentTransformer.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/DocumentWriter.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/DocumentWriter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/DocumentWriter.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/DocumentWriter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/MetadataMode.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/MetadataMode.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/MetadataMode.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/MetadataMode.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/id/IdGenerator.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/id/IdGenerator.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/id/IdGenerator.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/id/IdGenerator.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/id/JdkSha256HexIdGenerator.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/id/JdkSha256HexIdGenerator.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/id/JdkSha256HexIdGenerator.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/id/JdkSha256HexIdGenerator.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/id/RandomIdGenerator.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/id/RandomIdGenerator.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/id/RandomIdGenerator.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/id/RandomIdGenerator.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/document/package-info.java b/spring-ai-commons/src/main/java/org/springframework/ai/document/package-info.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/document/package-info.java rename to spring-ai-commons/src/main/java/org/springframework/ai/document/package-info.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/BatchingStrategy.java b/spring-ai-commons/src/main/java/org/springframework/ai/embedding/BatchingStrategy.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/BatchingStrategy.java rename to spring-ai-commons/src/main/java/org/springframework/ai/embedding/BatchingStrategy.java index 714d681a5..b49ad9871 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/embedding/BatchingStrategy.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/embedding/BatchingStrategy.java @@ -39,4 +39,4 @@ public interface BatchingStrategy { */ List> batch(List documents); -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/TokenCountBatchingStrategy.java b/spring-ai-commons/src/main/java/org/springframework/ai/embedding/TokenCountBatchingStrategy.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/TokenCountBatchingStrategy.java rename to spring-ai-commons/src/main/java/org/springframework/ai/embedding/TokenCountBatchingStrategy.java index 7ffc01fee..6ad13f0a4 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/embedding/TokenCountBatchingStrategy.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/embedding/TokenCountBatchingStrategy.java @@ -169,4 +169,4 @@ public class TokenCountBatchingStrategy implements BatchingStrategy { return batches; } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/Content.java b/spring-ai-commons/src/main/java/org/springframework/ai/model/Content.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/model/Content.java rename to spring-ai-commons/src/main/java/org/springframework/ai/model/Content.java index 1496d89a0..7bbb850db 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/model/Content.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/model/Content.java @@ -41,4 +41,4 @@ public interface Content { */ Map getMetadata(); -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/Media.java b/spring-ai-commons/src/main/java/org/springframework/ai/model/Media.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/Media.java rename to spring-ai-commons/src/main/java/org/springframework/ai/model/Media.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/MediaContent.java b/spring-ai-commons/src/main/java/org/springframework/ai/model/MediaContent.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/model/MediaContent.java rename to spring-ai-commons/src/main/java/org/springframework/ai/model/MediaContent.java index 865315c54..2aa665055 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/model/MediaContent.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/model/MediaContent.java @@ -25,4 +25,4 @@ public interface MediaContent extends Content { */ List getMedia(); -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/AiOperationMetadata.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/AiOperationMetadata.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/AiOperationMetadata.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/AiOperationMetadata.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationAttributes.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationAttributes.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationAttributes.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationAttributes.java index 2931ec5c8..a3b191f60 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationAttributes.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationAttributes.java @@ -151,4 +151,4 @@ public enum AiObservationAttributes { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationEventNames.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationEventNames.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationEventNames.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationEventNames.java index 2b1e87ecf..5f8bf1702 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationEventNames.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationEventNames.java @@ -56,4 +56,4 @@ public enum AiObservationEventNames { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricAttributes.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricAttributes.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricAttributes.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricAttributes.java index 03f4aacd0..9fc8aacf3 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricAttributes.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricAttributes.java @@ -51,4 +51,4 @@ public enum AiObservationMetricAttributes { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricNames.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricNames.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricNames.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricNames.java index 0a03a85ef..98ffdd8f8 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricNames.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiObservationMetricNames.java @@ -52,4 +52,4 @@ public enum AiObservationMetricNames { return this.value; } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiOperationType.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiOperationType.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiOperationType.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiOperationType.java index 8efc00e0e..c6924ae6d 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiOperationType.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiOperationType.java @@ -72,4 +72,4 @@ public enum AiOperationType { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiProvider.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiProvider.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiProvider.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiProvider.java index e723b679b..6ac043b61 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiProvider.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiProvider.java @@ -117,4 +117,4 @@ public enum AiProvider { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiTokenType.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiTokenType.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiTokenType.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiTokenType.java index 28da8df97..3bbf4cbd9 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/AiTokenType.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/AiTokenType.java @@ -59,4 +59,4 @@ public enum AiTokenType { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/SpringAiKind.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/SpringAiKind.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/SpringAiKind.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/SpringAiKind.java index 4f0a4b28e..be43282b3 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/SpringAiKind.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/SpringAiKind.java @@ -58,4 +58,4 @@ public enum SpringAiKind { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java index 7e411bd7c..d5258fb53 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java @@ -119,4 +119,4 @@ public enum VectorStoreObservationAttributes { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationEventNames.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationEventNames.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationEventNames.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationEventNames.java index 702f9517f..8f85c9a18 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationEventNames.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationEventNames.java @@ -47,4 +47,4 @@ public enum VectorStoreObservationEventNames { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java index a9c3e3f2b..53154864b 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java @@ -151,4 +151,4 @@ public enum VectorStoreProvider { return this.value; } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreSimilarityMetric.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreSimilarityMetric.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreSimilarityMetric.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreSimilarityMetric.java index 9a1ac00ca..5da9f8269 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreSimilarityMetric.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/VectorStoreSimilarityMetric.java @@ -63,4 +63,4 @@ public enum VectorStoreSimilarityMetric { // @formatter:on -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/package-info.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/package-info.java similarity index 94% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/package-info.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/package-info.java index d17ac5680..adda1d9ed 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/package-info.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/conventions/package-info.java @@ -22,4 +22,4 @@ package org.springframework.ai.observation.conventions; import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.springframework.lang.NonNullFields; \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/package-info.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/package-info.java similarity index 74% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/package-info.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/package-info.java index aefc3e1dc..841f9c5b2 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/package-info.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/package-info.java @@ -15,11 +15,6 @@ */ /** - * Provides classes for observing events in the system. + * Core observation abstractions. */ -@NonNullApi -@NonNullFields -package org.springframework.ai.observation; - -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +package org.springframework.ai.observation; \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/tracing/TracingHelper.java b/spring-ai-commons/src/main/java/org/springframework/ai/observation/tracing/TracingHelper.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/observation/tracing/TracingHelper.java rename to spring-ai-commons/src/main/java/org/springframework/ai/observation/tracing/TracingHelper.java index a675fd98e..5791400b8 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/tracing/TracingHelper.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/observation/tracing/TracingHelper.java @@ -78,4 +78,4 @@ public final class TracingHelper { return stringsJoiner.toString(); } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/tokenizer/JTokkitTokenCountEstimator.java b/spring-ai-commons/src/main/java/org/springframework/ai/tokenizer/JTokkitTokenCountEstimator.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/tokenizer/JTokkitTokenCountEstimator.java rename to spring-ai-commons/src/main/java/org/springframework/ai/tokenizer/JTokkitTokenCountEstimator.java index b5f0523d8..bb49a447c 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/tokenizer/JTokkitTokenCountEstimator.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/tokenizer/JTokkitTokenCountEstimator.java @@ -87,4 +87,4 @@ public class JTokkitTokenCountEstimator implements TokenCountEstimator { return totalSize; } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/tokenizer/TokenCountEstimator.java b/spring-ai-commons/src/main/java/org/springframework/ai/tokenizer/TokenCountEstimator.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/tokenizer/TokenCountEstimator.java rename to spring-ai-commons/src/main/java/org/springframework/ai/tokenizer/TokenCountEstimator.java index e33c464e9..b9c819c8f 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/tokenizer/TokenCountEstimator.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/tokenizer/TokenCountEstimator.java @@ -48,4 +48,4 @@ public interface TokenCountEstimator { */ int estimate(Iterable messages); -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/util/JacksonUtils.java b/spring-ai-commons/src/main/java/org/springframework/ai/util/JacksonUtils.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/util/JacksonUtils.java rename to spring-ai-commons/src/main/java/org/springframework/ai/util/JacksonUtils.java index 3686dd417..20453e287 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/util/JacksonUtils.java +++ b/spring-ai-commons/src/main/java/org/springframework/ai/util/JacksonUtils.java @@ -88,4 +88,4 @@ public abstract class JacksonUtils { return modules; } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/test/java/org/springframework/ai/document/ContentFormatterTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/document/ContentFormatterTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/document/ContentFormatterTests.java rename to spring-ai-commons/src/test/java/org/springframework/ai/document/ContentFormatterTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/document/DocumentBuilderTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentBuilderTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/document/DocumentBuilderTests.java rename to spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentBuilderTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/document/DocumentTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/document/DocumentTests.java rename to spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/document/id/IdGeneratorProviderTest.java b/spring-ai-commons/src/test/java/org/springframework/ai/document/id/IdGeneratorProviderTest.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/document/id/IdGeneratorProviderTest.java rename to spring-ai-commons/src/test/java/org/springframework/ai/document/id/IdGeneratorProviderTest.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/document/id/JdkSha256HexIdGeneratorTest.java b/spring-ai-commons/src/test/java/org/springframework/ai/document/id/JdkSha256HexIdGeneratorTest.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/document/id/JdkSha256HexIdGeneratorTest.java rename to spring-ai-commons/src/test/java/org/springframework/ai/document/id/JdkSha256HexIdGeneratorTest.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/embedding/TokenCountBatchingStrategyTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/embedding/TokenCountBatchingStrategyTests.java similarity index 99% rename from spring-ai-core/src/test/java/org/springframework/ai/embedding/TokenCountBatchingStrategyTests.java rename to spring-ai-commons/src/test/java/org/springframework/ai/embedding/TokenCountBatchingStrategyTests.java index 3d14f1e71..c2622c519 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/embedding/TokenCountBatchingStrategyTests.java +++ b/spring-ai-commons/src/test/java/org/springframework/ai/embedding/TokenCountBatchingStrategyTests.java @@ -54,4 +54,4 @@ public class TokenCountBatchingStrategyTests { .isInstanceOf(IllegalArgumentException.class); } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/test/java/org/springframework/ai/observation/AiOperationMetadataTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/observation/AiOperationMetadataTests.java similarity index 99% rename from spring-ai-core/src/test/java/org/springframework/ai/observation/AiOperationMetadataTests.java rename to spring-ai-commons/src/test/java/org/springframework/ai/observation/AiOperationMetadataTests.java index d538245b2..0ba5c4125 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/observation/AiOperationMetadataTests.java +++ b/spring-ai-commons/src/test/java/org/springframework/ai/observation/AiOperationMetadataTests.java @@ -63,4 +63,4 @@ class AiOperationMetadataTests { .hasMessageContaining("provider cannot be null or empty"); } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/test/java/org/springframework/ai/observation/tracing/TracingHelperTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/observation/tracing/TracingHelperTests.java similarity index 99% rename from spring-ai-core/src/test/java/org/springframework/ai/observation/tracing/TracingHelperTests.java rename to spring-ai-commons/src/test/java/org/springframework/ai/observation/tracing/TracingHelperTests.java index 78ed778b2..35b0996f6 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/observation/tracing/TracingHelperTests.java +++ b/spring-ai-commons/src/test/java/org/springframework/ai/observation/tracing/TracingHelperTests.java @@ -140,4 +140,4 @@ class TracingHelperTests { } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/test/kotlin/org/springframework/ai/utils/JacksonUtilsKotlinTests.kt b/spring-ai-commons/src/test/kotlin/org/springframework/ai/utils/JacksonUtilsKotlinTests.kt similarity index 99% rename from spring-ai-core/src/test/kotlin/org/springframework/ai/utils/JacksonUtilsKotlinTests.kt rename to spring-ai-commons/src/test/kotlin/org/springframework/ai/utils/JacksonUtilsKotlinTests.kt index 465bbe9df..876e4ea0b 100644 --- a/spring-ai-core/src/test/kotlin/org/springframework/ai/utils/JacksonUtilsKotlinTests.kt +++ b/spring-ai-commons/src/test/kotlin/org/springframework/ai/utils/JacksonUtilsKotlinTests.kt @@ -42,4 +42,4 @@ class JacksonUtilsKotlinTests { data class User(val name: String, val age: Int) -} +} \ No newline at end of file diff --git a/spring-ai-commons/src/test/resources/text_source.txt b/spring-ai-commons/src/test/resources/text_source.txt new file mode 100644 index 000000000..5f777418d --- /dev/null +++ b/spring-ai-commons/src/test/resources/text_source.txt @@ -0,0 +1,4124 @@ + + Spring Framework Documentation + + + Version 6.0.0 + + Chapter 1. Spring Framework Overview + + + Spring makes it easy to create Java enterprise applications. It provides everything you need to + embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as + alternative languages on the JVM, and with the flexibility to create many kinds of architectures + depending on an application’s needs. As of Spring Framework 5.1, Spring requires JDK 8+ (Java SE + 8+) and provides out-of-the-box support for JDK 11 LTS. Java SE 8 update 60 is suggested as the + minimum patch release for Java 8, but it is generally recommended to use a recent patch release. + + Spring supports a wide range of application scenarios. In a large enterprise, applications often exist + for a long time and have to run on a JDK and application server whose upgrade cycle is beyond + developer control. Others may run as a single jar with the server embedded, possibly in a cloud + environment. Yet others may be standalone applications (such as batch or integration workloads) + that do not need a server. + + + Spring is open source. It has a large and active community that provides continuous feedback based + on a diverse range of real-world use cases. This has helped Spring to successfully evolve over a very + long time. + + 1.1. What We Mean by "Spring" + + + The term "Spring" means different things in different contexts. It can be used to refer to the Spring + Framework project itself, which is where it all started. Over time, other Spring projects have been + built on top of the Spring Framework. Most often, when people say "Spring", they mean the entire + family of projects. This reference documentation focuses on the foundation: the Spring Framework + itself. + + + The Spring Framework is divided into modules. Applications can choose which modules they need. + At the heart are the modules of the core container, including a configuration model and a + dependency injection mechanism. Beyond that, the Spring Framework provides foundational + support for different application architectures, including messaging, transactional data and + persistence, and web. It also includes the Servlet-based Spring MVC web framework and, in + parallel, the Spring WebFlux reactive web framework. + + + A note about modules: Spring’s framework jars allow for deployment to JDK 9’s module path + ("Jigsaw"). For use in Jigsaw-enabled applications, the Spring Framework 5 jars come with + "Automatic-Module-Name" manifest entries which define stable language-level module names + ("spring.core", "spring.context", etc.) independent from jar artifact names (the jars follow the same + naming pattern with "-" instead of ".", e.g. "spring-core" and "spring-context"). Of course, Spring’s + framework jars keep working fine on the classpath on both JDK 8 and 9+. + + 1.2. History of Spring and the Spring Framework + + + Spring came into being in 2003 as a response to the complexity of the early J2EE specifications. + While some consider Java EE and its modern-day successor Jakarta EE to be in competition with + Spring, they are in fact complementary. The Spring programming model does not embrace the + Jakarta EE platform specification; rather, it integrates with carefully selected individual + + specifications from the traditional EE umbrella: + + + • Servlet API (JSR 340) + + • WebSocket API (JSR 356) + + • Concurrency Utilities (JSR 236) + + • JSON Binding API (JSR 367) + + • Bean Validation (JSR 303) + + • JPA (JSR 338) + + • JMS (JSR 914) + + • as well as JTA/JCA setups for transaction coordination, if necessary. + + + The Spring Framework also supports the Dependency Injection (JSR 330) and Common Annotations + (JSR 250) specifications, which application developers may choose to use instead of the Spring- + specific mechanisms provided by the Spring Framework. Originally, those were based on common + javax packages. + + As of Spring Framework 6.0, Spring has been upgraded to the Jakarta EE 9 level (e.g. Servlet 5.0+, + JPA 3.0+), based on the jakarta namespace instead of the traditional javax packages. With EE 9 as + the minimum and EE 10 supported already, Spring is prepared to provide out-of-the-box support + for the further evolution of the Jakarta EE APIs. Spring Framework 6.0 is fully compatible with + Tomcat 10.1, Jetty 11 and Undertow 2.3 as web servers, and also with Hibernate ORM 6.1. + + + Over time, the role of Java/Jakarta EE in application development has evolved. In the early days of + J2EE and Spring, applications were created to be deployed to an application server. Today, with the + help of Spring Boot, applications are created in a devops- and cloud-friendly way, with the Servlet + container embedded and trivial to change. As of Spring Framework 5, a WebFlux application does + not even use the Servlet API directly and can run on servers (such as Netty) that are not Servlet + containers. + + + Spring continues to innovate and to evolve. Beyond the Spring Framework, there are other projects, + such as Spring Boot, Spring Security, Spring Data, Spring Cloud, Spring Batch, among others. It’s + important to remember that each project has its own source code repository, issue tracker, and + release cadence. See spring.io/projects for the complete list of Spring projects. + + 1.3. Design Philosophy + + + When you learn about a framework, it’s important to know not only what it does but what + principles it follows. Here are the guiding principles of the Spring Framework: + + + • Provide choice at every level. Spring lets you defer design decisions as late as possible. For + example, you can switch persistence providers through configuration without changing your + code. The same is true for many other infrastructure concerns and integration with third-party + APIs. + + • Accommodate diverse perspectives. Spring embraces flexibility and is not opinionated about + how things should be done. It supports a wide range of application needs with different + perspectives. + + • Maintain strong backward compatibility. Spring’s evolution has been carefully managed to + force few breaking changes between versions. Spring supports a carefully chosen range of JDK + versions and third-party libraries to facilitate maintenance of applications and libraries that + depend on Spring. + + • Care about API design. The Spring team puts a lot of thought and time into making APIs that are + intuitive and that hold up across many versions and many years. + + • Set high standards for code quality. The Spring Framework puts a strong emphasis on + meaningful, current, and accurate javadoc. It is one of very few projects that can claim clean + code structure with no circular dependencies between packages. + + 1.4. Feedback and Contributions + + + For how-to questions or diagnosing or debugging issues, we suggest using Stack Overflow. Click + here for a list of the suggested tags to use on Stack Overflow. If you’re fairly certain that there is a + problem in the Spring Framework or would like to suggest a feature, please use the GitHub Issues. + + If you have a solution in mind or a suggested fix, you can submit a pull request on Github. + However, please keep in mind that, for all but the most trivial issues, we expect a ticket to be filed + in the issue tracker, where discussions take place and leave a record for future reference. + + + For more details see the guidelines at the CONTRIBUTING, top-level project page. + + 1.5. Getting Started + + + If you are just getting started with Spring, you may want to begin using the Spring Framework by + creating a Spring Boot-based application. Spring Boot provides a quick (and opinionated) way to + create a production-ready Spring-based application. It is based on the Spring Framework, favors + convention over configuration, and is designed to get you up and running as quickly as possible. + + + You can use start.spring.io to generate a basic project or follow one of the "Getting Started" guides, + such as Getting Started Building a RESTful Web Service. As well as being easier to digest, these + guides are very task focused, and most of them are based on Spring Boot. They also cover other + projects from the Spring portfolio that you might want to consider when solving a particular + problem. + + Chapter 2. Core Technologies + + + This part of the reference documentation covers all the technologies that are absolutely integral to + the Spring Framework. + + + Foremost amongst these is the Spring Framework’s Inversion of Control (IoC) container. A thorough + treatment of the Spring Framework’s IoC container is closely followed by comprehensive coverage + of Spring’s Aspect-Oriented Programming (AOP) technologies. The Spring Framework has its own + AOP framework, which is conceptually easy to understand and which successfully addresses the + 80% sweet spot of AOP requirements in Java enterprise programming. + + + Coverage of Spring’s integration with AspectJ (currently the richest — in terms of features — and + certainly most mature AOP implementation in the Java enterprise space) is also provided. + + + AOT processing can be used to optimize your application ahead-of-time. It is typically used for + native image deployment using GraalVM. + + 2.1. The IoC Container + + + This chapter covers Spring’s Inversion of Control (IoC) container. + + + 2.1.1. Introduction to the Spring IoC Container and Beans + + This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) + principle. IoC is also known as dependency injection (DI). It is a process whereby objects define + their dependencies (that is, the other objects they work with) only through constructor arguments, + arguments to a factory method, or properties that are set on the object instance after it is + constructed or returned from a factory method. The container then injects those dependencies + when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of + Control) of the bean itself controlling the instantiation or location of its dependencies by using + direct construction of classes or a mechanism such as the Service Locator pattern. + + + The org.springframework.beans and org.springframework.context packages are the basis for Spring + Framework’s IoC container. The BeanFactory interface provides an advanced configuration + mechanism capable of managing any type of object. ApplicationContext is a sub-interface of + BeanFactory. It adds: + + + • Easier integration with Spring’s AOP features + + • Message resource handling (for use in internationalization) + + • Event publication + + • Application-layer specific contexts such as the WebApplicationContext for use in web + applications. + + + In short, the BeanFactory provides the configuration framework and basic functionality, and the + ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a + complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of + Spring’s IoC container. For more information on using the BeanFactory instead of the + + ApplicationContext, see the section covering the BeanFactory API. + + + In Spring, the objects that form the backbone of your application and that are managed by the + Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and + managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your + application. Beans, and the dependencies among them, are reflected in the configuration metadata + used by a container. + + + 2.1.2. Container Overview + + The org.springframework.context.ApplicationContext interface represents the Spring IoC container + and is responsible for instantiating, configuring, and assembling the beans. The container gets its + instructions on what objects to instantiate, configure, and assemble by reading configuration + metadata. The configuration metadata is represented in XML, Java annotations, or Java code. It lets + you express the objects that compose your application and the rich interdependencies between + those objects. + + + Several implementations of the ApplicationContext interface are supplied with Spring. In stand- + alone applications, it is common to create an instance of ClassPathXmlApplicationContext or + FileSystemXmlApplicationContext. While XML has been the traditional format for defining + configuration metadata, you can instruct the container to use Java annotations or code as the + metadata format by providing a small amount of XML configuration to declaratively enable support + for these additional metadata formats. + + + In most application scenarios, explicit user code is not required to instantiate one or more + instances of a Spring IoC container. For example, in a web application scenario, a simple eight (or + so) lines of boilerplate web descriptor XML in the web.xml file of the application typically suffices + (see Convenient ApplicationContext Instantiation for Web Applications). If you use the Spring Tools + for Eclipse (an Eclipse-powered development environment), you can easily create this boilerplate + configuration with a few mouse clicks or keystrokes. + + + The following diagram shows a high-level view of how Spring works. Your application classes are + combined with configuration metadata so that, after the ApplicationContext is created and + initialized, you have a fully configured and executable system or application. + + Figure 1. The Spring IoC container + + + Configuration Metadata + + As the preceding diagram shows, the Spring IoC container consumes a form of configuration + metadata. This configuration metadata represents how you, as an application developer, tell the + Spring container to instantiate, configure, and assemble the objects in your application. + + + Configuration metadata is traditionally supplied in a simple and intuitive XML format, which is + what most of this chapter uses to convey key concepts and features of the Spring IoC container. + + + XML-based metadata is not the only allowed form of configuration metadata. The + Spring IoC container itself is totally decoupled from the format in which this +  configuration metadata is actually written. These days, many developers choose + Java-based configuration for their Spring applications. + + + For information about using other forms of metadata with the Spring container, see: + + + • Annotation-based configuration: Spring 2.5 introduced support for annotation-based + configuration metadata. + + • Java-based configuration: Starting with Spring 3.0, many features provided by the Spring + JavaConfig project became part of the core Spring Framework. Thus, you can define beans + external to your application classes by using Java rather than XML files. To use these new + features, see the @Configuration, @Bean, @Import, and @DependsOn annotations. + + Spring configuration consists of at least one and typically more than one bean definition that the + container must manage. XML-based configuration metadata configures these beans as + elements inside a top-level element. Java configuration typically uses @Bean-annotated + methods within a @Configuration class. + + These bean definitions correspond to the actual objects that make up your application. Typically, + you define service layer objects, data access objects (DAOs), presentation objects such as Struts + Action instances, infrastructure objects such as Hibernate SessionFactories, JMS Queues, and so + forth. Typically, one does not configure fine-grained domain objects in the container, because it is + + usually the responsibility of DAOs and business logic to create and load domain objects. However, + you can use Spring’s integration with AspectJ to configure objects that have been created outside + the control of an IoC container. See Using AspectJ to dependency-inject domain objects with Spring. + + + The following example shows the basic structure of XML-based configuration metadata: + + + + + + + +   ① ② +   +   + + +   +   +   + + +   + + + + + + ① The id attribute is a string that identifies the individual bean definition. + + ② The class attribute defines the type of the bean and uses the fully qualified classname. + + The value of the id attribute refers to collaborating objects. The XML for referring to collaborating + objects is not shown in this example. See Dependencies for more information. + + + Instantiating a Container + + The location path or paths supplied to an ApplicationContext constructor are resource strings that + let the container load configuration metadata from a variety of external resources, such as the local + file system, the Java CLASSPATH, and so on. + + + Java + + + ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", + "daos.xml"); + + + + Kotlin + + + val context = ClassPathXmlApplicationContext("services.xml", "daos.xml") + + After you learn about Spring’s IoC container, you may want to know more about + Spring’s Resource abstraction (as described in Resources), which provides a +  convenient mechanism for reading an InputStream from locations defined in a + URI syntax. In particular, Resource paths are used to construct applications + contexts, as described in Application Contexts and Resource Paths. + + + The following example shows the service layer objects (services.xml) configuration file: + + + + + + + +   + + +   +   +   +   +   + + +   + + + + + + + The following example shows the data access objects daos.xml file: + + + + + + + +   +   +   + + +   +   +   + + +   + + + + + In the preceding example, the service layer consists of the PetStoreServiceImpl class and two data + access objects of the types JpaAccountDao and JpaItemDao (based on the JPA Object-Relational + Mapping standard). The property name element refers to the name of the JavaBean property, and the + ref element refers to the name of another bean definition. This linkage between id and ref + elements expresses the dependency between collaborating objects. For details of configuring an + object’s dependencies, see Dependencies. + + + + Composing XML-based Configuration Metadata + + It can be useful to have bean definitions span multiple XML files. Often, each individual XML + configuration file represents a logical layer or module in your architecture. + + + You can use the application context constructor to load bean definitions from all these XML + fragments. This constructor takes multiple Resource locations, as was shown in the previous section. + Alternatively, use one or more occurrences of the element to load bean definitions from + another file or files. The following example shows how to do so: + + + + +   +   +   + + +   +   + + + + + In the preceding example, external bean definitions are loaded from three files: services.xml, + messageSource.xml, and themeSource.xml. All location paths are relative to the definition file doing + the importing, so services.xml must be in the same directory or classpath location as the file doing + the importing, while messageSource.xml and themeSource.xml must be in a resources location below + the location of the importing file. As you can see, a leading slash is ignored. However, given that + these paths are relative, it is better form not to use the slash at all. The contents of the files being + imported, including the top level element, must be valid XML bean definitions, according + to the Spring Schema. + + It is possible, but not recommended, to reference files in parent directories using a + relative "../" path. Doing so creates a dependency on a file that is outside the + current application. In particular, this reference is not recommended for + classpath: URLs (for example, classpath:../services.xml), where the runtime + resolution process chooses the “nearest” classpath root and then looks into its + parent directory. Classpath configuration changes may lead to the choice of a + different, incorrect directory. +  + You can always use fully qualified resource locations instead of relative paths: for + example, file:C:/config/services.xml or classpath:/config/services.xml. + However, be aware that you are coupling your application’s configuration to + specific absolute locations. It is generally preferable to keep an indirection for such + absolute locations — for example, through "${…}" placeholders that are resolved + against JVM system properties at runtime. + + + The namespace itself provides the import directive feature. Further configuration features beyond + plain bean definitions are available in a selection of XML namespaces provided by Spring — for + example, the context and util namespaces. + + + + The Groovy Bean Definition DSL + + As a further example for externalized configuration metadata, bean definitions can also be + expressed in Spring’s Groovy Bean Definition DSL, as known from the Grails framework. Typically, + such configuration live in a ".groovy" file with the structure shown in the following example: + + + + beans { +   dataSource(BasicDataSource) { +   driverClassName = "org.hsqldb.jdbcDriver" +   url = "jdbc:hsqldb:mem:grailsDB" +   username = "sa" +   password = "" +   settings = [mynew:"setting"] +   } +   sessionFactory(SessionFactory) { +   dataSource = dataSource +   } +   myService(MyService) { +   nestedBean = { AnotherBean bean -> +   dataSource = dataSource +   } +   } + } + + + + This configuration style is largely equivalent to XML bean definitions and even supports Spring’s + XML configuration namespaces. It also allows for importing XML bean definition files through an + importBeans directive. + + Using the Container + + The ApplicationContext is the interface for an advanced factory capable of maintaining a registry of + different beans and their dependencies. By using the method T getBean(String name, Class + requiredType), you can retrieve instances of your beans. + + The ApplicationContext lets you read bean definitions and access them, as the following example + shows: + + + Java + + + // create and configure beans + ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", + "daos.xml"); + + + // retrieve configured instance + PetStoreService service = context.getBean("petStore", PetStoreService.class); + + + // use configured instance + List userList = service.getUsernameList(); + + + + Kotlin + + + import org.springframework.beans.factory.getBean + + + // create and configure beans + val context = ClassPathXmlApplicationContext("services.xml", "daos.xml") + + + // retrieve configured instance + val service = context.getBean("petStore") + + + // use configured instance + var userList = service.getUsernameList() + + + + With Groovy configuration, bootstrapping looks very similar. It has a different context + implementation class which is Groovy-aware (but also understands XML bean definitions). The + following example shows Groovy configuration: + + + Java + + + ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", + "daos.groovy"); + + + + Kotlin + + + val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy") + + + + The most flexible variant is GenericApplicationContext in combination with reader delegates — for + example, with XmlBeanDefinitionReader for XML files, as the following example shows: + + Java + + + GenericApplicationContext context = new GenericApplicationContext(); + new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml"); + context.refresh(); + + + + Kotlin + + + val context = GenericApplicationContext() + XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml") + context.refresh() + + + + You can also use the GroovyBeanDefinitionReader for Groovy files, as the following example shows: + + + Java + + + GenericApplicationContext context = new GenericApplicationContext(); + new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", + "daos.groovy"); + context.refresh(); + + + + Kotlin + + + val context = GenericApplicationContext() + GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", + "daos.groovy") + context.refresh() + + + + You can mix and match such reader delegates on the same ApplicationContext, reading bean + definitions from diverse configuration sources. + + + You can then use getBean to retrieve instances of your beans. The ApplicationContext interface has a + few other methods for retrieving beans, but, ideally, your application code should never use them. + Indeed, your application code should have no calls to the getBean() method at all and thus have no + dependency on Spring APIs at all. For example, Spring’s integration with web frameworks provides + dependency injection for various web framework components such as controllers and JSF-managed + beans, letting you declare a dependency on a specific bean through metadata (such as an + autowiring annotation). + + + 2.1.3. Bean Overview + + A Spring IoC container manages one or more beans. These beans are created with the configuration + metadata that you supply to the container (for example, in the form of XML definitions). + + + Within the container itself, these bean definitions are represented as BeanDefinition objects, which + contain (among other information) the following metadata: + + • A package-qualified class name: typically, the actual implementation class of the bean being + + defined. + + • Bean behavioral configuration elements, which state how the bean should behave in the + container (scope, lifecycle callbacks, and so forth). + + • References to other beans that are needed for the bean to do its work. These references are also + called collaborators or dependencies. + + • Other configuration settings to set in the newly created object — for example, the size limit of + the pool or the number of connections to use in a bean that manages a connection pool. + + + This metadata translates to a set of properties that make up each bean definition. The following + table describes these properties: + + + Table 1. The bean definition + + Property Explained in… + + Class Instantiating Beans + + Name Naming Beans + + Scope Bean Scopes + + Constructor arguments Dependency Injection + + Properties Dependency Injection + + Autowiring mode Autowiring Collaborators + + Lazy initialization mode Lazy-initialized Beans + + Initialization method Initialization Callbacks + + Destruction method Destruction Callbacks + + + In addition to bean definitions that contain information on how to create a specific bean, the + ApplicationContext implementations also permit the registration of existing objects that are created + outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory + through the getBeanFactory() method, which returns the DefaultListableBeanFactory + implementation. DefaultListableBeanFactory supports this registration through the + registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications + work solely with beans defined through regular bean definition metadata. + + + Bean metadata and manually supplied singleton instances need to be registered as + early as possible, in order for the container to properly reason about them during + autowiring and other introspection steps. While overriding existing metadata and +  existing singleton instances is supported to some degree, the registration of new + beans at runtime (concurrently with live access to the factory) is not officially + supported and may lead to concurrent access exceptions, inconsistent state in the + bean container, or both. + + + + Naming Beans + + Every bean has one or more identifiers. These identifiers must be unique within the container that + hosts the bean. A bean usually has only one identifier. However, if it requires more than one, the + + extra ones can be considered aliases. + + + In XML-based configuration metadata, you use the id attribute, the name attribute, or both to specify + the bean identifiers. The id attribute lets you specify exactly one id. Conventionally, these names + are alphanumeric ('myBean', 'someService', etc.), but they can contain special characters as well. If + you want to introduce other aliases for the bean, you can also specify them in the name attribute, + separated by a comma (,), semicolon (;), or white space. As a historical note, in versions prior to + Spring 3.1, the id attribute was defined as an xsd:ID type, which constrained possible characters. As + of 3.1, it is defined as an xsd:string type. Note that bean id uniqueness is still enforced by the + container, though no longer by XML parsers. + + + You are not required to supply a name or an id for a bean. If you do not supply a name or id explicitly, + the container generates a unique name for that bean. However, if you want to refer to that bean by + name, through the use of the ref element or a Service Locator style lookup, you must provide a + name. Motivations for not supplying a name are related to using inner beans and autowiring + collaborators. + + + Bean Naming Conventions + + The convention is to use the standard Java convention for instance field names when naming + beans. That is, bean names start with a lowercase letter and are camel-cased from there. + Examples of such names include accountManager, accountService, userDao, loginController, and + so forth. + + + Naming beans consistently makes your configuration easier to read and understand. Also, if + you use Spring AOP, it helps a lot when applying advice to a set of beans related by name. + + + + + With component scanning in the classpath, Spring generates bean names for + unnamed components, following the rules described earlier: essentially, taking the + simple class name and turning its initial character to lower-case. However, in the +  (unusual) special case when there is more than one character and both the first + and second characters are upper case, the original casing gets preserved. These are + the same rules as defined by java.beans.Introspector.decapitalize (which Spring + uses here). + + + + Aliasing a Bean outside the Bean Definition + + In a bean definition itself, you can supply more than one name for the bean, by using a + combination of up to one name specified by the id attribute and any number of other names in the + name attribute. These names can be equivalent aliases to the same bean and are useful for some + situations, such as letting each component in an application refer to a common dependency by + using a bean name that is specific to that component itself. + + Specifying all aliases where the bean is actually defined is not always adequate, however. It is + sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly + the case in large systems where configuration is split amongst each subsystem, with each + subsystem having its own set of object definitions. In XML-based configuration metadata, you can + use the element to accomplish this. The following example shows how to do so: + + + + + + In this case, a bean (in the same container) named fromName may also, after the use of this alias + definition, be referred to as toName. + + + For example, the configuration metadata for subsystem A may refer to a DataSource by the name of + subsystemA-dataSource. The configuration metadata for subsystem B may refer to a DataSource by + the name of subsystemB-dataSource. When composing the main application that uses both these + subsystems, the main application refers to the DataSource by the name of myApp-dataSource. To have + all three names refer to the same object, you can add the following alias definitions to the + configuration metadata: + + + + + + + + + Now each component and the main application can refer to the dataSource through a name that is + unique and guaranteed not to clash with any other definition (effectively creating a namespace), + yet they refer to the same bean. + + + Java-configuration + + If you use Javaconfiguration, the @Bean annotation can be used to provide aliases. See Using + the @Bean Annotation for details. + + + + + Instantiating Beans + + A bean definition is essentially a recipe for creating one or more objects. The container looks at the + recipe for a named bean when asked and uses the configuration metadata encapsulated by that + bean definition to create (or acquire) an actual object. + + + If you use XML-based configuration metadata, you specify the type (or class) of object that is to be + instantiated in the class attribute of the element. This class attribute (which, internally, is a + Class property on a BeanDefinition instance) is usually mandatory. (For exceptions, see + Instantiation by Using an Instance Factory Method and Bean Definition Inheritance.) You can use + the Class property in one of two ways: + + + • Typically, to specify the bean class to be constructed in the case where the container itself + directly creates the bean by calling its constructor reflectively, somewhat equivalent to Java + code with the new operator. + + • To specify the actual class containing the static factory method that is invoked to create the + object, in the less common case where the container invokes a static factory method on a class + to create the bean. The object type returned from the invocation of the static factory method + may be the same class or another class entirely. + + Nested class names + + If you want to configure a bean definition for a nested class, you may use either the binary + name or the source name of the nested class. + + + For example, if you have a class called SomeThing in the com.example package, and this + SomeThing class has a static nested class called OtherThing, they can be separated by a dollar + sign ($) or a dot (.). So the value of the class attribute in a bean definition would be + com.example.SomeThing$OtherThing or com.example.SomeThing.OtherThing. + + + + + + Instantiation with a Constructor + + When you create a bean by the constructor approach, all normal classes are usable by and + compatible with Spring. That is, the class being developed does not need to implement any specific + interfaces or to be coded in a specific fashion. Simply specifying the bean class should suffice. + However, depending on what type of IoC you use for that specific bean, you may need a default + (empty) constructor. + + + The Spring IoC container can manage virtually any class you want it to manage. It is not limited to + managing true JavaBeans. Most Spring users prefer actual JavaBeans with only a default (no- + argument) constructor and appropriate setters and getters modeled after the properties in the + container. You can also have more exotic non-bean-style classes in your container. If, for example, + you need to use a legacy connection pool that absolutely does not adhere to the JavaBean + specification, Spring can manage it as well. + + + With XML-based configuration metadata you can specify your bean class as follows: + + + + + + + + + + + For details about the mechanism for supplying arguments to the constructor (if required) and + setting object instance properties after the object is constructed, see Injecting Dependencies. + + + + Instantiation with a Static Factory Method + + When defining a bean that you create with a static factory method, use the class attribute to specify + the class that contains the static factory method and an attribute named factory-method to specify + the name of the factory method itself. You should be able to call this method (with optional + arguments, as described later) and return a live object, which subsequently is treated as if it had + been created through a constructor. One use for such a bean definition is to call static factories in + legacy code. + + + The following bean definition specifies that the bean will be created by calling a factory method. + The definition does not specify the type (class) of the returned object, but rather the class + containing the factory method. In this example, the createInstance() method must be a static + method. The following example shows how to specify a factory method: + + + + + + The following example shows a class that would work with the preceding bean definition: + + + Java + + + public class ClientService { +   private static ClientService clientService = new ClientService(); +   private ClientService() {} + + +   public static ClientService createInstance() { +   return clientService; +   } + } + + + + Kotlin + + + class ClientService private constructor() { +   companion object { +   private val clientService = ClientService() +   @JvmStatic +   fun createInstance() = clientService +   } + } + + + + For details about the mechanism for supplying (optional) arguments to the factory method and + setting object instance properties after the object is returned from the factory, see Dependencies + and Configuration in Detail. + + + + Instantiation by Using an Instance Factory Method + + Similar to instantiation through a static factory method, instantiation with an instance factory + method invokes a non-static method of an existing bean from the container to create a new bean. + To use this mechanism, leave the class attribute empty and, in the factory-bean attribute, specify + the name of a bean in the current (or parent or ancestor) container that contains the instance + method that is to be invoked to create the object. Set the name of the factory method itself with the + factory-method attribute. The following example shows how to configure such a bean: + + + +   + + + + + + + + + The following example shows the corresponding class: + + + Java + + + public class DefaultServiceLocator { + + +   private static ClientService clientService = new ClientServiceImpl(); + + +   public ClientService createClientServiceInstance() { +   return clientService; +   } + } + + + + Kotlin + + + class DefaultServiceLocator { +   companion object { +   private val clientService = ClientServiceImpl() +   } +   fun createClientServiceInstance(): ClientService { +   return clientService +   } + } + + + + One factory class can also hold more than one factory method, as the following example shows: + + + + +   + + + + + + + + + The following example shows the corresponding class: + + + Java + + + public class DefaultServiceLocator { + + +   private static ClientService clientService = new ClientServiceImpl(); + + +   private static AccountService accountService = new AccountServiceImpl(); + + +   public ClientService createClientServiceInstance() { +   return clientService; +   } + + +   public AccountService createAccountServiceInstance() { +   return accountService; +   } + } + + + + Kotlin + + + class DefaultServiceLocator { +   companion object { +   private val clientService = ClientServiceImpl() +   private val accountService = AccountServiceImpl() +   } + + +   fun createClientServiceInstance(): ClientService { +   return clientService +   } + + +   fun createAccountServiceInstance(): AccountService { +   return accountService +   } + } + + + + This approach shows that the factory bean itself can be managed and configured through + dependency injection (DI). See Dependencies and Configuration in Detail. + + + In Spring documentation, "factory bean" refers to a bean that is configured in the + Spring container and that creates objects through an instance or static factory +  method. By contrast, FactoryBean (notice the capitalization) refers to a Spring- + specific FactoryBean implementation class. + + + + Determining a Bean’s Runtime Type + + The runtime type of a specific bean is non-trivial to determine. A specified class in the bean + metadata definition is just an initial class reference, potentially combined with a declared factory + method or being a FactoryBean class which may lead to a different runtime type of the bean, or not + + being set at all in case of an instance-level factory method (which is resolved via the specified + factory-bean name instead). Additionally, AOP proxying may wrap a bean instance with an + interface-based proxy with limited exposure of the target bean’s actual type (just its implemented + interfaces). + + The recommended way to find out about the actual runtime type of a particular bean is a + BeanFactory.getType call for the specified bean name. This takes all of the above cases into account + and returns the type of object that a BeanFactory.getBean call is going to return for the same bean + name. + + 2.1.4. Dependencies + + A typical enterprise application does not consist of a single object (or bean in the Spring parlance). + Even the simplest application has a few objects that work together to present what the end-user + sees as a coherent application. This next section explains how you go from defining a number of + bean definitions that stand alone to a fully realized application where objects collaborate to achieve + a goal. + + + Dependency Injection + + Dependency injection (DI) is a process whereby objects define their dependencies (that is, the other + objects with which they work) only through constructor arguments, arguments to a factory method, + or properties that are set on the object instance after it is constructed or returned from a factory + method. The container then injects those dependencies when it creates the bean. This process is + fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the + instantiation or location of its dependencies on its own by using direct construction of classes or the + Service Locator pattern. + + + Code is cleaner with the DI principle, and decoupling is more effective when objects are provided + with their dependencies. The object does not look up its dependencies and does not know the + location or class of the dependencies. As a result, your classes become easier to test, particularly + when the dependencies are on interfaces or abstract base classes, which allow for stub or mock + implementations to be used in unit tests. + + + DI exists in two major variants: Constructor-based dependency injection and Setter-based + dependency injection. + + + + Constructor-based Dependency Injection + + Constructor-based DI is accomplished by the container invoking a constructor with a number of + arguments, each representing a dependency. Calling a static factory method with specific + arguments to construct the bean is nearly equivalent, and this discussion treats arguments to a + constructor and to a static factory method similarly. The following example shows a class that can + only be dependency-injected with constructor injection: + + Java + + + public class SimpleMovieLister { + + +   // the SimpleMovieLister has a dependency on a MovieFinder +   private final MovieFinder movieFinder; + + +   // a constructor so that the Spring container can inject a MovieFinder +   public SimpleMovieLister(MovieFinder movieFinder) { +   this.movieFinder = movieFinder; +   } + + +   // business logic that actually uses the injected MovieFinder is omitted... + } + + + + Kotlin + + + // a constructor so that the Spring container can inject a MovieFinder + class SimpleMovieLister(private val movieFinder: MovieFinder) { +   // business logic that actually uses the injected MovieFinder is omitted... + } + + + + Notice that there is nothing special about this class. It is a POJO that has no dependencies on + container specific interfaces, base classes, or annotations. + + + Constructor Argument Resolution + + Constructor argument resolution matching occurs by using the argument’s type. If no potential + ambiguity exists in the constructor arguments of a bean definition, the order in which the + constructor arguments are defined in a bean definition is the order in which those arguments are + supplied to the appropriate constructor when the bean is being instantiated. Consider the following + class: + + + Java + + + package x.y; + + + public class ThingOne { + + +   public ThingOne(ThingTwo thingTwo, ThingThree thingThree) { +   // ... +   } + } + + Kotlin + + + package x.y + + + class ThingOne(thingTwo: ThingTwo, thingThree: ThingThree) + + + + Assuming that the ThingTwo and ThingThree classes are not related by inheritance, no potential + ambiguity exists. Thus, the following configuration works fine, and you do not need to specify the + constructor argument indexes or types explicitly in the element. + + + + +   +   +   +   + + +   + + +   + + + + + When another bean is referenced, the type is known, and matching can occur (as was the case with + the preceding example). When a simple type is used, such as true, Spring cannot + determine the type of the value, and so cannot match by type without help. Consider the following + class: + + + Java + + + package examples; + + + public class ExampleBean { + + +   // Number of years to calculate the Ultimate Answer +   private final int years; + + +   // The Answer to Life, the Universe, and Everything +   private final String ultimateAnswer; + + +   public ExampleBean(int years, String ultimateAnswer) { +   this.years = years; +   this.ultimateAnswer = ultimateAnswer; +   } + } + + Kotlin + + + package examples + + + class ExampleBean( +   private val years: Int, // Number of years to calculate the Ultimate Answer +   private val ultimateAnswer: String // The Answer to Life, the Universe, and + Everything + ) + + + + Constructor argument type matching + In the preceding scenario, the container can use type matching with simple types if you explicitly + specify the type of the constructor argument by using the type attribute, as the following example + shows: + + + + +   +   + + + + + Constructor argument index + You can use the index attribute to specify explicitly the index of constructor arguments, as the + following example shows: + + + + +   +   + + + + + In addition to resolving the ambiguity of multiple simple values, specifying an index resolves + ambiguity where a constructor has two arguments of the same type. + +  The index is 0-based. + + + Constructor argument name + You can also use the constructor parameter name for value disambiguation, as the following + example shows: + + + + +   +   + + + + + Keep in mind that, to make this work out of the box, your code must be compiled with the debug + flag enabled so that Spring can look up the parameter name from the constructor. If you cannot or + + do not want to compile your code with the debug flag, you can use the @ConstructorProperties JDK + annotation to explicitly name your constructor arguments. The sample class would then have to + look as follows: + + + Java + + + package examples; + + + public class ExampleBean { + + +   // Fields omitted + + +   @ConstructorProperties({"years", "ultimateAnswer"}) +   public ExampleBean(int years, String ultimateAnswer) { +   this.years = years; +   this.ultimateAnswer = ultimateAnswer; +   } + } + + + + Kotlin + + + package examples + + + class ExampleBean + @ConstructorProperties("years", "ultimateAnswer") + constructor(val years: Int, val ultimateAnswer: String) + + + + + Setter-based Dependency Injection + + Setter-based DI is accomplished by the container calling setter methods on your beans after + invoking a no-argument constructor or a no-argument static factory method to instantiate your + bean. + + The following example shows a class that can only be dependency-injected by using pure setter + injection. This class is conventional Java. It is a POJO that has no dependencies on container specific + interfaces, base classes, or annotations. + + Java + + + public class SimpleMovieLister { + + +   // the SimpleMovieLister has a dependency on the MovieFinder +   private MovieFinder movieFinder; + + +   // a setter method so that the Spring container can inject a MovieFinder +   public void setMovieFinder(MovieFinder movieFinder) { +   this.movieFinder = movieFinder; +   } + + +   // business logic that actually uses the injected MovieFinder is omitted... + } + + + + Kotlin + + + class SimpleMovieLister { + + +   // a late-initialized property so that the Spring container can inject a + MovieFinder +   lateinit var movieFinder: MovieFinder + + +   // business logic that actually uses the injected MovieFinder is omitted... + } + + + + The ApplicationContext supports constructor-based and setter-based DI for the beans it manages. It + also supports setter-based DI after some dependencies have already been injected through the + constructor approach. You configure the dependencies in the form of a BeanDefinition, which you + use in conjunction with PropertyEditor instances to convert properties from one format to another. + However, most Spring users do not work with these classes directly (that is, programmatically) but + rather with XML bean definitions, annotated components (that is, classes annotated with @Component, + @Controller, and so forth), or @Bean methods in Java-based @Configuration classes. These sources are + then converted internally into instances of BeanDefinition and used to load an entire Spring IoC + container instance. + + Constructor-based or setter-based DI? + + Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use + constructors for mandatory dependencies and setter methods or configuration methods for + optional dependencies. Note that use of the @Autowired annotation on a setter method can + be used to make the property be a required dependency; however, constructor injection with + programmatic validation of arguments is preferable. + + The Spring team generally advocates constructor injection, as it lets you implement + application components as immutable objects and ensures that required dependencies are + not null. Furthermore, constructor-injected components are always returned to the client + (calling) code in a fully initialized state. As a side note, a large number of constructor + arguments is a bad code smell, implying that the class likely has too many responsibilities and + should be refactored to better address proper separation of concerns. + + + Setter injection should primarily only be used for optional dependencies that can be assigned + reasonable default values within the class. Otherwise, not-null checks must be performed + everywhere the code uses the dependency. One benefit of setter injection is that setter + methods make objects of that class amenable to reconfiguration or re-injection later. + Management through JMX MBeans is therefore a compelling use case for setter injection. + + + Use the DI style that makes the most sense for a particular class. Sometimes, when dealing + with third-party classes for which you do not have the source, the choice is made for you. For + example, if a third-party class does not expose any setter methods, then constructor injection + may be the only available form of DI. + + + + + + Dependency Resolution Process + + The container performs bean dependency resolution as follows: + + + • The ApplicationContext is created and initialized with configuration metadata that describes all + the beans. Configuration metadata can be specified by XML, Java code, or annotations. + + • For each bean, its dependencies are expressed in the form of properties, constructor arguments, + or arguments to the static-factory method (if you use that instead of a normal constructor). + These dependencies are provided to the bean, when the bean is actually created. + + • Each property or constructor argument is an actual definition of the value to set, or a reference + to another bean in the container. + + • Each property or constructor argument that is a value is converted from its specified format to + the actual type of that property or constructor argument. By default, Spring can convert a value + supplied in string format to all built-in types, such as int, long, String, boolean, and so forth. + + The Spring container validates the configuration of each bean as the container is created. However, + the bean properties themselves are not set until the bean is actually created. Beans that are + singleton-scoped and set to be pre-instantiated (the default) are created when the container is + created. Scopes are defined in Bean Scopes. Otherwise, the bean is created only when it is + requested. Creation of a bean potentially causes a graph of beans to be created, as the bean’s + dependencies and its dependencies' dependencies (and so on) are created and assigned. Note that + + resolution mismatches among those dependencies may show up late — that is, on first creation of + the affected bean. + + + Circular dependencies + + If you use predominantly constructor injection, it is possible to create an unresolvable + circular dependency scenario. + + + For example: Class A requires an instance of class B through constructor injection, and class B + requires an instance of class A through constructor injection. If you configure beans for + classes A and B to be injected into each other, the Spring IoC container detects this circular + reference at runtime, and throws a BeanCurrentlyInCreationException. + + + One possible solution is to edit the source code of some classes to be configured by setters + rather than constructors. Alternatively, avoid constructor injection and use setter injection + only. In other words, although it is not recommended, you can configure circular + dependencies with setter injection. + + + Unlike the typical case (with no circular dependencies), a circular dependency between bean + A and bean B forces one of the beans to be injected into the other prior to being fully + initialized itself (a classic chicken-and-egg scenario). + + + + You can generally trust Spring to do the right thing. It detects configuration problems, such as + references to non-existent beans and circular dependencies, at container load-time. Spring sets + properties and resolves dependencies as late as possible, when the bean is actually created. This + means that a Spring container that has loaded correctly can later generate an exception when you + request an object if there is a problem creating that object or one of its dependencies — for + example, the bean throws an exception as a result of a missing or invalid property. This potentially + delayed visibility of some configuration issues is why ApplicationContext implementations by + default pre-instantiate singleton beans. At the cost of some upfront time and memory to create + these beans before they are actually needed, you discover configuration issues when the + ApplicationContext is created, not later. You can still override this default behavior so that singleton + beans initialize lazily, rather than being eagerly pre-instantiated. + + + If no circular dependencies exist, when one or more collaborating beans are being injected into a + dependent bean, each collaborating bean is totally configured prior to being injected into the + dependent bean. This means that, if bean A has a dependency on bean B, the Spring IoC container + completely configures bean B prior to invoking the setter method on bean A. In other words, the + bean is instantiated (if it is not a pre-instantiated singleton), its dependencies are set, and the + relevant lifecycle methods (such as a configured init method or the InitializingBean callback + method) are invoked. + + + + Examples of Dependency Injection + + The following example uses XML-based configuration metadata for setter-based DI. A small part of + a Spring XML configuration file specifies some bean definitions as follows: + + +   +   +   +   + + +   +   +   + + + + + + + + + The following example shows the corresponding ExampleBean class: + + + Java + + + public class ExampleBean { + + +   private AnotherBean beanOne; + + +   private YetAnotherBean beanTwo; + + +   private int i; + + +   public void setBeanOne(AnotherBean beanOne) { +   this.beanOne = beanOne; +   } + + +   public void setBeanTwo(YetAnotherBean beanTwo) { +   this.beanTwo = beanTwo; +   } + + +   public void setIntegerProperty(int i) { +   this.i = i; +   } + } + + + + Kotlin + + + class ExampleBean { +   lateinit var beanOne: AnotherBean +   lateinit var beanTwo: YetAnotherBean +   var i: Int = 0 + } + + + + In the preceding example, setters are declared to match against the properties specified in the XML + + file. The following example uses constructor-based DI: + + + + +   +   +   +   + + +   +   + + +   + + + + + + + + + The following example shows the corresponding ExampleBean class: + + + Java + + + public class ExampleBean { + + +   private AnotherBean beanOne; + + +   private YetAnotherBean beanTwo; + + +   private int i; + + +   public ExampleBean( +   AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { +   this.beanOne = anotherBean; +   this.beanTwo = yetAnotherBean; +   this.i = i; +   } + } + + + + Kotlin + + + class ExampleBean( +   private val beanOne: AnotherBean, +   private val beanTwo: YetAnotherBean, +   private val i: Int) + + + + The constructor arguments specified in the bean definition are used as arguments to the + constructor of the ExampleBean. + + + Now consider a variant of this example, where, instead of using a constructor, Spring is told to call + a static factory method to return an instance of the object: + + +   +   +   + + + + + + + + + The following example shows the corresponding ExampleBean class: + + + Java + + + public class ExampleBean { + + +   // a private constructor +   private ExampleBean(...) { +   ... +   } + + +   // a static factory method; the arguments to this method can be +   // considered the dependencies of the bean that is returned, +   // regardless of how those arguments are actually used. +   public static ExampleBean createInstance ( +   AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { + + +   ExampleBean eb = new ExampleBean (...); +   // some other operations... +   return eb; +   } + } + + + + Kotlin + + + class ExampleBean private constructor() { +   companion object { +   // a static factory method; the arguments to this method can be +   // considered the dependencies of the bean that is returned, +   // regardless of how those arguments are actually used. +   @JvmStatic +   fun createInstance(anotherBean: AnotherBean, yetAnotherBean: YetAnotherBean, + i: Int): ExampleBean { +   val eb = ExampleBean (...) +   // some other operations... +   return eb +   } +   } + } + + Arguments to the static factory method are supplied by elements, exactly the + same as if a constructor had actually been used. The type of the class being returned by the factory + method does not have to be of the same type as the class that contains the static factory method + (although, in this example, it is). An instance (non-static) factory method can be used in an + essentially identical fashion (aside from the use of the factory-bean attribute instead of the class + attribute), so we do not discuss those details here. + + + Dependencies and Configuration in Detail + + As mentioned in the previous section, you can define bean properties and constructor arguments as + references to other managed beans (collaborators) or as values defined inline. Spring’s XML-based + configuration metadata supports sub-element types within its and + elements for this purpose. + + + + Straight Values (Primitives, Strings, and so on) + + The value attribute of the element specifies a property or constructor argument as a + human-readable string representation. Spring’s conversion service is used to convert these values + from a String to the actual type of the property or argument. The following example shows various + values being set: + + + + +   +   +   +   +   + + + + + The following example uses the p-namespace for even more succinct XML configuration: + + + + + + +   + + + + + + + The preceding XML is more succinct. However, typos are discovered at runtime rather than design + + time, unless you use an IDE (such as IntelliJ IDEA or the Spring Tools for Eclipse) that supports + automatic property completion when you create bean definitions. Such IDE assistance is highly + recommended. + + + You can also configure a java.util.Properties instance, as follows: + + + + + + +   +   +   +   jdbc.driver.className=com.mysql.jdbc.Driver +   jdbc.url=jdbc:mysql://localhost:3306/mydb +   +   + + + + + The Spring container converts the text inside the element into a java.util.Properties + instance by using the JavaBeans PropertyEditor mechanism. This is a nice shortcut, and is one of a + few places where the Spring team do favor the use of the nested element over the value + attribute style. + + + The idref element + + The idref element is simply an error-proof way to pass the id (a string value - not a reference) of + another bean in the container to a or element. The following + example shows how to use it: + + + + + + + +   +   +   + + + + + The preceding bean definition snippet is exactly equivalent (at runtime) to the following snippet: + + + + + + + +   + + + + + The first form is preferable to the second, because using the idref tag lets the container validate at + deployment time that the referenced, named bean actually exists. In the second variation, no + + validation is performed on the value that is passed to the targetName property of the client bean. + Typos are only discovered (with most likely fatal results) when the client bean is actually + instantiated. If the client bean is a prototype bean, this typo and the resulting exception may only + be discovered long after the container is deployed. + + + The local attribute on the idref element is no longer supported in the 4.0 beans + XSD, since it does not provide value over a regular bean reference any more. +  Change your existing idref local references to idref bean when upgrading to the + 4.0 schema. + + + A common place (at least in versions earlier than Spring 2.0) where the element brings + value is in the configuration of AOP interceptors in a ProxyFactoryBean bean definition. Using + elements when you specify the interceptor names prevents you from misspelling an + interceptor ID. + + + + References to Other Beans (Collaborators) + + The ref element is the final element inside a or definition element. + Here, you set the value of the specified property of a bean to be a reference to another bean (a + collaborator) managed by the container. The referenced bean is a dependency of the bean whose + property is to be set, and it is initialized on demand as needed before the property is set. (If the + collaborator is a singleton bean, it may already be initialized by the container.) All references are + ultimately a reference to another object. Scoping and validation depend on whether you specify the + ID or name of the other object through the bean or parent attribute. + + + Specifying the target bean through the bean attribute of the tag is the most general form and + allows creation of a reference to any bean in the same container or parent container, regardless of + whether it is in the same XML file. The value of the bean attribute may be the same as the id + attribute of the target bean or be the same as one of the values in the name attribute of the target + bean. The following example shows how to use a ref element: + + + + + + + + Specifying the target bean through the parent attribute creates a reference to a bean that is in a + parent container of the current container. The value of the parent attribute may be the same as + either the id attribute of the target bean or one of the values in the name attribute of the target bean. + The target bean must be in a parent container of the current one. You should use this bean + reference variant mainly when you have a hierarchy of containers and you want to wrap an + existing bean in a parent container with a proxy that has the same name as the parent bean. The + following pair of listings shows how to use the parent attribute: + + + + + +   + + + + +   class="org.springframework.aop.framework.ProxyFactoryBean"> +   +   +   +   + + + + + + The local attribute on the ref element is no longer supported in the 4.0 beans XSD, +  since it does not provide value over a regular bean reference any more. Change + your existing ref local references to ref bean when upgrading to the 4.0 schema. + + + + Inner Beans + + A element inside the or elements defines an inner bean, as + the following example shows: + + + + +   +   +   +   +   +   +   + + + + + An inner bean definition does not require a defined ID or name. If specified, the container does not + use such a value as an identifier. The container also ignores the scope flag on creation, because + inner beans are always anonymous and are always created with the outer bean. It is not possible to + access inner beans independently or to inject them into collaborating beans other than into the + enclosing bean. + + + As a corner case, it is possible to receive destruction callbacks from a custom scope — for example, + for a request-scoped inner bean contained within a singleton bean. The creation of the inner bean + instance is tied to its containing bean, but destruction callbacks let it participate in the request + scope’s lifecycle. This is not a common scenario. Inner beans typically simply share their containing + bean’s scope. + + + + Collections + + The , , , and elements set the properties and arguments of the Java + Collection types List, Set, Map, and Properties, respectively. The following example shows how to + use them: + + +   +   +   +   administrator@example.org +   support@example.org +   development@example.org +   +   +   +   +   +   a list element followed by a reference +   +   +   +   +   +   +   +   +   +   +   +   +   +   just some string +   +   +   + + + + + The value of a map key or value, or a set value, can also be any of the following elements: + + + + bean | ref | idref | list | set | map | props | value | null + + + + Collection Merging + + The Spring container also supports merging collections. An application developer can define a + parent , , or element and have child , , or + elements inherit and override values from the parent collection. That is, the child collection’s + values are the result of merging the elements of the parent and child collections, with the child’s + collection elements overriding values specified in the parent collection. + + + This section on merging discusses the parent-child bean mechanism. Readers unfamiliar with + parent and child bean definitions may wish to read the relevant section before continuing. + + + The following example demonstrates collection merging: + + +   +   +   +   administrator@example.com +   support@example.com +   +   +   +   +   +   +   +   sales@example.com +   support@example.co.uk +   +   +   + + + + + Notice the use of the merge=true attribute on the element of the adminEmails property of the + child bean definition. When the child bean is resolved and instantiated by the container, the + resulting instance has an adminEmails Properties collection that contains the result of merging the + child’s adminEmails collection with the parent’s adminEmails collection. The following listing shows + the result: + + + + administrator=administrator@example.com + sales=sales@example.com + support=support@example.co.uk + + + + The child Properties collection’s value set inherits all property elements from the parent , + and the child’s value for the support value overrides the value in the parent collection. + + + This merging behavior applies similarly to the , , and collection types. In the + specific case of the element, the semantics associated with the List collection type (that is, + the notion of an ordered collection of values) is maintained. The parent’s values precede all of the + child list’s values. In the case of the Map, Set, and Properties collection types, no ordering exists. + Hence, no ordering semantics are in effect for the collection types that underlie the associated Map, + Set, and Properties implementation types that the container uses internally. + + + Limitations of Collection Merging + + You cannot merge different collection types (such as a Map and a List). If you do attempt to do so, an + appropriate Exception is thrown. The merge attribute must be specified on the lower, inherited, child + definition. Specifying the merge attribute on a parent collection definition is redundant and does not + result in the desired merging. + + Strongly-typed collection + + Thanks to Java’s support for generic types, you can use strongly typed collections. That is, it is + possible to declare a Collection type such that it can only contain (for example) String elements. If + you use Spring to dependency-inject a strongly-typed Collection into a bean, you can take + advantage of Spring’s type-conversion support such that the elements of your strongly-typed + Collection instances are converted to the appropriate type prior to being added to the Collection. + The following Java class and bean definition show how to do so: + + + Java + + + public class SomeClass { + + +   private Map accounts; + + +   public void setAccounts(Map accounts) { +   this.accounts = accounts; +   } + } + + + + Kotlin + + + class SomeClass { +   lateinit var accounts: Map + } + + + + + +   +   +   +   +   +   +   +   +   + + + + + When the accounts property of the something bean is prepared for injection, the generics + information about the element type of the strongly-typed Map is available by + reflection. Thus, Spring’s type conversion infrastructure recognizes the various value elements as + being of type Float, and the string values (9.99, 2.75, and 3.99) are converted into an actual Float + type. + + + + Null and Empty String Values + + Spring treats empty arguments for properties and the like as empty Strings. The following XML- + based configuration metadata snippet sets the email property to the empty String value (""). + + +   + + + + + The preceding example is equivalent to the following Java code: + + + Java + + + exampleBean.setEmail(""); + + + + Kotlin + + + exampleBean.email = "" + + + + The element handles null values. The following listing shows an example: + + + + +   +   +   + + + + + The preceding configuration is equivalent to the following Java code: + + + Java + + + exampleBean.setEmail(null); + + + + Kotlin + + + exampleBean.email = null + + + + + XML Shortcut with the p-namespace + + The p-namespace lets you use the bean element’s attributes (instead of nested elements) + to describe your property values collaborating beans, or both. + + + Spring supports extensible configuration formats with namespaces, which are based on an XML + Schema definition. The beans configuration format discussed in this chapter is defined in an XML + Schema document. However, the p-namespace is not defined in an XSD file and exists only in the + core of Spring. + + + The following example shows two XML snippets (the first uses standard XML format and the + second uses the p-namespace) that resolve to the same result: + + + + +   +   +   + + +   + + + + + The example shows an attribute in the p-namespace called email in the bean definition. This tells + Spring to include a property declaration. As previously mentioned, the p-namespace does not have + a schema definition, so you can set the name of the attribute to the property name. + + + This next example includes two more bean definitions that both have a reference to another bean: + + + + + + +   +   +   +   + + +   + + +   +   +   + + + + + This example includes not only a property value using the p-namespace but also uses a special + format to declare property references. Whereas the first bean definition uses to create a reference from bean john to bean jane, the second bean + definition uses p:spouse-ref="jane" as an attribute to do the exact same thing. In this case, spouse is + the property name, whereas the -ref part indicates that this is not a straight value but rather a + reference to another bean. + + The p-namespace is not as flexible as the standard XML format. For example, the + format for declaring property references clashes with properties that end in Ref, +  whereas the standard XML format does not. We recommend that you choose your + approach carefully and communicate this to your team members to avoid + producing XML documents that use all three approaches at the same time. + + + + XML Shortcut with the c-namespace + + Similar to the XML Shortcut with the p-namespace, the c-namespace, introduced in Spring 3.1, + allows inlined attributes for configuring the constructor arguments rather then nested constructor- + arg elements. + + + The following example uses the c: namespace to do the same thing as the from Constructor-based + Dependency Injection: + + + + + + +   +   + + +   +   +   +   +   +   + + +   +   + + + + + + + The c: namespace uses the same conventions as the p: one (a trailing -ref for bean references) for + setting the constructor arguments by their names. Similarly, it needs to be declared in the XML file + even though it is not defined in an XSD schema (it exists inside the Spring core). + + For the rare cases where the constructor argument names are not available (usually if the bytecode + was compiled without debugging information), you can use fallback to the argument indexes, as + follows: + + + + + + + + Due to the XML grammar, the index notation requires the presence of the leading + _, as XML attribute names cannot start with a number (even though some IDEs +  allow it). A corresponding index notation is also available for + elements but not commonly used since the plain order of declaration is usually + sufficient there. + + + In practice, the constructor resolution mechanism is quite efficient in matching arguments, so + unless you really need to, we recommend using the name notation throughout your configuration. + + + + Compound Property Names + + You can use compound or nested property names when you set bean properties, as long as all + components of the path except the final property name are not null. Consider the following bean + definition: + + + + +   + + + + + The something bean has a fred property, which has a bob property, which has a sammy property, and + that final sammy property is being set to a value of 123. In order for this to work, the fred property of + something and the bob property of fred must not be null after the bean is constructed. Otherwise, a + NullPointerException is thrown. + + + Using depends-on + + If a bean is a dependency of another bean, that usually means that one bean is set as a property of + another. Typically you accomplish this with the element in XML-based configuration + metadata. However, sometimes dependencies between beans are less direct. An example is when a + static initializer in a class needs to be triggered, such as for database driver registration. The + depends-on attribute can explicitly force one or more beans to be initialized before the bean using + this element is initialized. The following example uses the depends-on attribute to express a + dependency on a single bean: + + + + + + + + + To express a dependency on multiple beans, supply a list of bean names as the value of the depends- + on attribute (commas, whitespace, and semicolons are valid delimiters): + + +   + + + + + + + + + + The depends-on attribute can specify both an initialization-time dependency and, in + the case of singleton beans only, a corresponding destruction-time dependency. +  Dependent beans that define a depends-on relationship with a given bean are + destroyed first, prior to the given bean itself being destroyed. Thus, depends-on can + also control shutdown order. + + + + Lazy-initialized Beans + + By default, ApplicationContext implementations eagerly create and configure all singleton beans as + part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the + configuration or surrounding environment are discovered immediately, as opposed to hours or + even days later. When this behavior is not desirable, you can prevent pre-instantiation of a + singleton bean by marking the bean definition as being lazy-initialized. A lazy-initialized bean tells + the IoC container to create a bean instance when it is first requested, rather than at startup. + + + In XML, this behavior is controlled by the lazy-init attribute on the element, as the + following example shows: + + + + + + + + + When the preceding configuration is consumed by an ApplicationContext, the lazy bean is not + eagerly pre-instantiated when the ApplicationContext starts, whereas the not.lazy bean is eagerly + pre-instantiated. + + + However, when a lazy-initialized bean is a dependency of a singleton bean that is not lazy- + initialized, the ApplicationContext creates the lazy-initialized bean at startup, because it must + satisfy the singleton’s dependencies. The lazy-initialized bean is injected into a singleton bean + elsewhere that is not lazy-initialized. + + You can also control lazy-initialization at the container level by using the default-lazy-init + attribute on the element, as the following example shows: + + + + +   + + + Autowiring Collaborators + + The Spring container can autowire relationships between collaborating beans. You can let Spring + resolve collaborators (other beans) automatically for your bean by inspecting the contents of the + ApplicationContext. Autowiring has the following advantages: + + • Autowiring can significantly reduce the need to specify properties or constructor arguments. + (Other mechanisms such as a bean template discussed elsewhere in this chapter are also + valuable in this regard.) + + • Autowiring can update a configuration as your objects evolve. For example, if you need to add a + dependency to a class, that dependency can be satisfied automatically without you needing to + modify the configuration. Thus autowiring can be especially useful during development, + without negating the option of switching to explicit wiring when the code base becomes more + stable. + + + When using XML-based configuration metadata (see Dependency Injection), you can specify the + autowire mode for a bean definition with the autowire attribute of the element. The + autowiring functionality has four modes. You specify autowiring per bean and can thus choose + which ones to autowire. The following table describes the four autowiring modes: + + + Table 2. Autowiring modes + + Mode Explanation + no (Default) No autowiring. Bean references must be defined by ref elements. + Changing the default setting is not recommended for larger deployments, + because specifying collaborators explicitly gives greater control and clarity. To + some extent, it documents the structure of a system. + byName Autowiring by property name. Spring looks for a bean with the same name as + the property that needs to be autowired. For example, if a bean definition is + set to autowire by name and it contains a master property (that is, it has a + setMaster(..) method), Spring looks for a bean definition named master and + uses it to set the property. + byType Lets a property be autowired if exactly one bean of the property type exists in + the container. If more than one exists, a fatal exception is thrown, which + indicates that you may not use byType autowiring for that bean. If there are no + matching beans, nothing happens (the property is not set). + constructor Analogous to byType but applies to constructor arguments. If there is not + exactly one bean of the constructor argument type in the container, a fatal + error is raised. + + + With byType or constructor autowiring mode, you can wire arrays and typed collections. In such + cases, all autowire candidates within the container that match the expected type are provided to + satisfy the dependency. You can autowire strongly-typed Map instances if the expected key type is + String. An autowired Map instance’s values consist of all bean instances that match the expected + type, and the Map instance’s keys contain the corresponding bean names. + + Limitations and Disadvantages of Autowiring + + Autowiring works best when it is used consistently across a project. If autowiring is not used in + general, it might be confusing to developers to use it to wire only one or two bean definitions. + + + Consider the limitations and disadvantages of autowiring: + + • Explicit dependencies in property and constructor-arg settings always override autowiring. You + cannot autowire simple properties such as primitives, Strings, and Classes (and arrays of such + simple properties). This limitation is by-design. + + • Autowiring is less exact than explicit wiring. Although, as noted in the earlier table, Spring is + careful to avoid guessing in case of ambiguity that might have unexpected results. The + relationships between your Spring-managed objects are no longer documented explicitly. + + • Wiring information may not be available to tools that may generate documentation from a + Spring container. + + • Multiple bean definitions within the container may match the type specified by the setter + method or constructor argument to be autowired. For arrays, collections, or Map instances, this is + not necessarily a problem. However, for dependencies that expect a single value, this ambiguity + is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown. + + + In the latter scenario, you have several options: + + • Abandon autowiring in favor of explicit wiring. + + • Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as + described in the next section. + + • Designate a single bean definition as the primary candidate by setting the primary attribute of its + element to true. + + • Implement the more fine-grained control available with annotation-based configuration, as + described in Annotation-based Container Configuration. + + + + Excluding a Bean from Autowiring + + On a per-bean basis, you can exclude a bean from autowiring. In Spring’s XML format, set the + autowire-candidate attribute of the element to false. The container makes that specific bean + definition unavailable to the autowiring infrastructure (including annotation style configurations + such as @Autowired). + + + The autowire-candidate attribute is designed to only affect type-based autowiring. + It does not affect explicit references by name, which get resolved even if the +  specified bean is not marked as an autowire candidate. As a consequence, + autowiring by name nevertheless injects a bean if the name matches. + + + You can also limit autowire candidates based on pattern-matching against bean names. The top- + level element accepts one or more patterns within its default-autowire-candidates + attribute. For example, to limit autowire candidate status to any bean whose name ends with + Repository, provide a value of *Repository. To provide multiple patterns, define them in a comma- + separated list. An explicit value of true or false for a bean definition’s autowire-candidate attribute + + always takes precedence. For such beans, the pattern matching rules do not apply. + + + These techniques are useful for beans that you never want to be injected into other beans by + autowiring. It does not mean that an excluded bean cannot itself be configured by using + autowiring. Rather, the bean itself is not a candidate for autowiring other beans. + + + Method Injection + + In most application scenarios, most beans in the container are singletons. When a singleton bean + needs to collaborate with another singleton bean or a non-singleton bean needs to collaborate with + another non-singleton bean, you typically handle the dependency by defining one bean as a + property of the other. A problem arises when the bean lifecycles are different. Suppose singleton + bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A. + The container creates the singleton bean A only once, and thus only gets one opportunity to set the + properties. The container cannot provide bean A with a new instance of bean B every time one is + needed. + + A solution is to forego some inversion of control. You can make bean A aware of the container by + implementing the ApplicationContextAware interface, and by making a getBean("B") call to the + container ask for (a typically new) bean B instance every time bean A needs it. The following + example shows this approach: + + Java + + + // a class that uses a stateful Command-style class to perform some processing + package fiona.apple; + + + // Spring-API imports + import org.springframework.beans.BeansException; + import org.springframework.context.ApplicationContext; + import org.springframework.context.ApplicationContextAware; + + + public class CommandManager implements ApplicationContextAware { + + +   private ApplicationContext applicationContext; + + +   public Object process(Map commandState) { +   // grab a new instance of the appropriate Command +   Command command = createCommand(); +   // set the state on the (hopefully brand new) Command instance +   command.setState(commandState); +   return command.execute(); +   } + + +   protected Command createCommand() { +   // notice the Spring API dependency! +   return this.applicationContext.getBean("command", Command.class); +   } + + +   public void setApplicationContext( +   ApplicationContext applicationContext) throws BeansException { +   this.applicationContext = applicationContext; +   } + } + + Kotlin + + + // a class that uses a stateful Command-style class to perform some processing + package fiona.apple + + + // Spring-API imports + import org.springframework.context.ApplicationContext + import org.springframework.context.ApplicationContextAware + + + class CommandManager : ApplicationContextAware { + + +   private lateinit var applicationContext: ApplicationContext + + +   fun process(commandState: Map<*, *>): Any { +   // grab a new instance of the appropriate Command +   val command = createCommand() +   // set the state on the (hopefully brand new) Command instance +   command.state = commandState +   return command.execute() +   } + + +   // notice the Spring API dependency! +   protected fun createCommand() = +   applicationContext.getBean("command", Command::class.java) + + +   override fun setApplicationContext(applicationContext: ApplicationContext) { +   this.applicationContext = applicationContext +   } + } + + + + The preceding is not desirable, because the business code is aware of and coupled to the Spring + Framework. Method Injection, a somewhat advanced feature of the Spring IoC container, lets you + handle this use case cleanly. + + + + You can read more about the motivation for Method Injection in this blog entry. + + + + + + Lookup Method Injection + + Lookup method injection is the ability of the container to override methods on container-managed + beans and return the lookup result for another named bean in the container. The lookup typically + involves a prototype bean, as in the scenario described in the preceding section. The Spring + Framework implements this method injection by using bytecode generation from the CGLIB library + to dynamically generate a subclass that overrides the method. + + • For this dynamic subclassing to work, the class that the Spring bean container + subclasses cannot be final, and the method to be overridden cannot be final, + either. + + • Unit-testing a class that has an abstract method requires you to subclass the + class yourself and to supply a stub implementation of the abstract method. +  • Concrete methods are also necessary for component scanning, which requires + concrete classes to pick up. + + • A further key limitation is that lookup methods do not work with factory + methods and in particular not with @Bean methods in configuration classes, + since, in that case, the container is not in charge of creating the instance and + therefore cannot create a runtime-generated subclass on the fly. + + + In the case of the CommandManager class in the previous code snippet, the Spring container + dynamically overrides the implementation of the createCommand() method. The CommandManager class + does not have any Spring dependencies, as the reworked example shows: + + + Java + + + package fiona.apple; + + + // no more Spring imports! + + + public abstract class CommandManager { + + +   public Object process(Object commandState) { +   // grab a new instance of the appropriate Command interface +   Command command = createCommand(); +   // set the state on the (hopefully brand new) Command instance +   command.setState(commandState); +   return command.execute(); +   } + + +   // okay... but where is the implementation of this method? +   protected abstract Command createCommand(); + } + + Kotlin + + + package fiona.apple + + + // no more Spring imports! + + + abstract class CommandManager { + + +   fun process(commandState: Any): Any { +   // grab a new instance of the appropriate Command interface +   val command = createCommand() +   // set the state on the (hopefully brand new) Command instance +   command.state = commandState +   return command.execute() +   } + + +   // okay... but where is the implementation of this method? +   protected abstract fun createCommand(): Command + } + + + + In the client class that contains the method to be injected (the CommandManager in this case), the + method to be injected requires a signature of the following form: + + + + [abstract] theMethodName(no-arguments); + + + + If the method is abstract, the dynamically-generated subclass implements the method. Otherwise, + the dynamically-generated subclass overrides the concrete method defined in the original class. + Consider the following example: + + + + + +   + + + + + +   + + + + + The bean identified as commandManager calls its own createCommand() method whenever it needs a + new instance of the myCommand bean. You must be careful to deploy the myCommand bean as a prototype + if that is actually what is needed. If it is a singleton, the same instance of the myCommand bean is + returned each time. + + + Alternatively, within the annotation-based component model, you can declare a lookup method + through the @Lookup annotation, as the following example shows: + + Java + + + public abstract class CommandManager { + + +   public Object process(Object commandState) { +   Command command = createCommand(); +   command.setState(commandState); +   return command.execute(); +   } + + +   @Lookup("myCommand") +   protected abstract Command createCommand(); + } + + + + Kotlin + + + abstract class CommandManager { + + +   fun process(commandState: Any): Any { +   val command = createCommand() +   command.state = commandState +   return command.execute() +   } + + +   @Lookup("myCommand") +   protected abstract fun createCommand(): Command + } + + + + Or, more idiomatically, you can rely on the target bean getting resolved against the declared return + type of the lookup method: + + + Java + + + public abstract class CommandManager { + + +   public Object process(Object commandState) { +   Command command = createCommand(); +   command.setState(commandState); +   return command.execute(); +   } + + +   @Lookup +   protected abstract Command createCommand(); + } + + Kotlin + + + abstract class CommandManager { + + +   fun process(commandState: Any): Any { +   val command = createCommand() +   command.state = commandState +   return command.execute() +   } + + +   @Lookup +   protected abstract fun createCommand(): Command + } + + + + Note that you should typically declare such annotated lookup methods with a concrete stub + implementation, in order for them to be compatible with Spring’s component scanning rules where + abstract classes get ignored by default. This limitation does not apply to explicitly registered or + explicitly imported bean classes. + + + Another way of accessing differently scoped target beans is an ObjectFactory/ + Provider injection point. See Scoped Beans as Dependencies. +  + You may also find the ServiceLocatorFactoryBean (in the + org.springframework.beans.factory.config package) to be useful. + + + + Arbitrary Method Replacement + + A less useful form of method injection than lookup method injection is the ability to replace + arbitrary methods in a managed bean with another method implementation. You can safely skip + the rest of this section until you actually need this functionality. + + + With XML-based configuration metadata, you can use the replaced-method element to replace an + existing method implementation with another, for a deployed bean. Consider the following class, + which has a method called computeValue that we want to override: + + + Java + + + public class MyValueCalculator { + + +   public String computeValue(String input) { +   // some real code... +   } + + +   // some other methods... + } + + Kotlin + + + class MyValueCalculator { + + +   fun computeValue(input: String): String { +   // some real code... +   } + + +   // some other methods... + } + + + + A class that implements the org.springframework.beans.factory.support.MethodReplacer interface + provides the new method definition, as the following example shows: + + + Java + + + /** +  * meant to be used to override the existing computeValue(String) +  * implementation in MyValueCalculator +  */ + public class ReplacementComputeValue implements MethodReplacer { + + +   public Object reimplement(Object o, Method m, Object[] args) throws Throwable { +   // get the input value, work with it, and return a computed result +   String input = (String) args[0]; +   ... +   return ...; +   } + } + + + + Kotlin + + + /** +  * meant to be used to override the existing computeValue(String) +  * implementation in MyValueCalculator +  */ + class ReplacementComputeValue : MethodReplacer { + + +   override fun reimplement(obj: Any, method: Method, args: Array): Any { +   // get the input value, work with it, and return a computed result +   val input = args[0] as String; +   ... +   return ...; +   } + } + + + + The bean definition to deploy the original class and specify the method override would resemble + the following example: + + +   +   +   String +   + + + + + + + + You can use one or more elements within the element to indicate + the method signature of the method being overridden. The signature for the arguments is + necessary only if the method is overloaded and multiple variants exist within the class. For + convenience, the type string for an argument may be a substring of the fully qualified type name. + For example, the following all match java.lang.String: + + + + java.lang.String + String + Str + + + + Because the number of arguments is often enough to distinguish between each possible choice, this + shortcut can save a lot of typing, by letting you type only the shortest string that matches an + argument type. + + 2.1.5. Bean Scopes + + When you create a bean definition, you create a recipe for creating actual instances of the class + defined by that bean definition. The idea that a bean definition is a recipe is important, because it + means that, as with a class, you can create many object instances from a single recipe. + + + You can control not only the various dependencies and configuration values that are to be plugged + into an object that is created from a particular bean definition but also control the scope of the + objects created from a particular bean definition. This approach is powerful and flexible, because + you can choose the scope of the objects you create through configuration instead of having to bake + in the scope of an object at the Java class level. Beans can be defined to be deployed in one of a + number of scopes. The Spring Framework supports six scopes, four of which are available only if + you use a web-aware ApplicationContext. You can also create a custom scope. + + The following table describes the supported scopes: + + + Table 3. Bean scopes + + Scope Description + + singleton (Default) Scopes a single bean definition to a single object instance for each + Spring IoC container. + + prototype Scopes a single bean definition to any number of object instances. + + Scope Description + + request Scopes a single bean definition to the lifecycle of a single HTTP request. That + is, each HTTP request has its own instance of a bean created off the back of a + single bean definition. Only valid in the context of a web-aware Spring + ApplicationContext. + + session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid + in the context of a web-aware Spring ApplicationContext. + + application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid + in the context of a web-aware Spring ApplicationContext. + + websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the + context of a web-aware Spring ApplicationContext. + + + + As of Spring 3.0, a thread scope is available but is not registered by default. For +  more information, see the documentation for SimpleThreadScope. For instructions + on how to register this or any other custom scope, see Using a Custom Scope. + + + + The Singleton Scope + + Only one shared instance of a singleton bean is managed, and all requests for beans with an ID or + IDs that match that bean definition result in that one specific bean instance being returned by the + Spring container. + + + To put it another way, when you define a bean definition and it is scoped as a singleton, the Spring + IoC container creates exactly one instance of the object defined by that bean definition. This single + instance is stored in a cache of such singleton beans, and all subsequent requests and references + for that named bean return the cached object. The following image shows how the singleton scope + works: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Spring’s concept of a singleton bean differs from the singleton pattern as defined in the Gang of + Four (GoF) patterns book. The GoF singleton hard-codes the scope of an object such that one and + + only one instance of a particular class is created per ClassLoader. The scope of the Spring singleton + is best described as being per-container and per-bean. This means that, if you define one bean for a + particular class in a single Spring container, the Spring container creates one and only one instance + of the class defined by that bean definition. The singleton scope is the default scope in Spring. To + define a bean as a singleton in XML, you can define a bean as shown in the following example: + + + + + + + + + + + + + The Prototype Scope + + The non-singleton prototype scope of bean deployment results in the creation of a new bean + instance every time a request for that specific bean is made. That is, the bean is injected into + another bean or you request it through a getBean() method call on the container. As a rule, you + should use the prototype scope for all stateful beans and the singleton scope for stateless beans. + + + The following diagram illustrates the Spring prototype scope: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (A data access object (DAO) is not typically configured as a prototype, because a typical DAO does + not hold any conversational state. It was easier for us to reuse the core of the singleton diagram.) + + The following example defines a bean as a prototype in XML: + + + + + + + + In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean. + + The container instantiates, configures, and otherwise assembles a prototype object and hands it to + the client, with no further record of that prototype instance. Thus, although initialization lifecycle + callback methods are called on all objects regardless of scope, in the case of prototypes, configured + destruction lifecycle callbacks are not called. The client code must clean up prototype-scoped + objects and release expensive resources that the prototype beans hold. To get the Spring container + to release resources held by prototype-scoped beans, try using a custom bean post-processor, which + holds a reference to beans that need to be cleaned up. + + + In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement + for the Java new operator. All lifecycle management past that point must be handled by the client. + (For details on the lifecycle of a bean in the Spring container, see Lifecycle Callbacks.) + + + Singleton Beans with Prototype-bean Dependencies + + When you use singleton-scoped beans with dependencies on prototype beans, be aware that + dependencies are resolved at instantiation time. Thus, if you dependency-inject a prototype-scoped + bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency- + injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to + the singleton-scoped bean. + + + However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype- + scoped bean repeatedly at runtime. You cannot dependency-inject a prototype-scoped bean into + your singleton bean, because that injection occurs only once, when the Spring container + instantiates the singleton bean and resolves and injects its dependencies. If you need a new + instance of a prototype bean at runtime more than once, see Method Injection. + + + Request, Session, Application, and WebSocket Scopes + + The request, session, application, and websocket scopes are available only if you use a web-aware + Spring ApplicationContext implementation (such as XmlWebApplicationContext). If you use these + scopes with regular Spring IoC containers, such as the ClassPathXmlApplicationContext, an + IllegalStateException that complains about an unknown bean scope is thrown. + + + + Initial Web Configuration + + To support the scoping of beans at the request, session, application, and websocket levels (web- + scoped beans), some minor initial configuration is required before you define your beans. (This + initial setup is not required for the standard scopes: singleton and prototype.) + + + How you accomplish this initial setup depends on your particular Servlet environment. + + + If you access scoped beans within Spring Web MVC, in effect, within a request that is processed by + the Spring DispatcherServlet, no special setup is necessary. DispatcherServlet already exposes all + relevant state. + + + If you use a Servlet web container, with requests processed outside of Spring’s DispatcherServlet + (for example, when using JSF or Struts), you need to register the + org.springframework.web.context.request.RequestContextListener ServletRequestListener. This can + be done programmatically by using the WebApplicationInitializer interface. Alternatively, add the + following declaration to your web application’s web.xml file: + + +   ... +   +   +   org.springframework.web.context.request.RequestContextListener +   +   +   ... + + + + + Alternatively, if there are issues with your listener setup, consider using Spring’s + RequestContextFilter. The filter mapping depends on the surrounding web application + configuration, so you have to change it as appropriate. The following listing shows the filter part of + a web application: + + + + +   ... +   +   requestContextFilter +   org.springframework.web.filter.RequestContextFilter +   +   +   requestContextFilter +   /* +   +   ... + + + + + DispatcherServlet, RequestContextListener, and RequestContextFilter all do exactly the same thing, + namely bind the HTTP request object to the Thread that is servicing that request. This makes beans + that are request- and session-scoped available further down the call chain. + + + + Request scope + + Consider the following XML configuration for a bean definition: + + + + + + + + The Spring container creates a new instance of the LoginAction bean by using the loginAction bean + definition for each and every HTTP request. That is, the loginAction bean is scoped at the HTTP + request level. You can change the internal state of the instance that is created as much as you want, + because other instances created from the same loginAction bean definition do not see these + changes in state. They are particular to an individual request. When the request completes + processing, the bean that is scoped to the request is discarded. + + + When using annotation-driven components or Java configuration, the @RequestScope annotation can + + be used to assign a component to the request scope. The following example shows how to do so: + + + Java + + + @RequestScope + @Component + public class LoginAction { +   // ... + } + + + + Kotlin + + + @RequestScope + @Component + class LoginAction { +   // ... + } + + + + + Session Scope + + Consider the following XML configuration for a bean definition: + + + + + + + + The Spring container creates a new instance of the UserPreferences bean by using the + userPreferences bean definition for the lifetime of a single HTTP Session. In other words, the + userPreferences bean is effectively scoped at the HTTP Session level. As with request-scoped beans, + you can change the internal state of the instance that is created as much as you want, knowing that + other HTTP Session instances that are also using instances created from the same userPreferences + bean definition do not see these changes in state, because they are particular to an individual HTTP + Session. When the HTTP Session is eventually discarded, the bean that is scoped to that particular + HTTP Session is also discarded. + + + When using annotation-driven components or Java configuration, you can use the @SessionScope + annotation to assign a component to the session scope. + + + Java + + + @SessionScope + @Component + public class UserPreferences { +   // ... + } + + Kotlin + + + @SessionScope + @Component + class UserPreferences { +   // ... + } + + + + + Application Scope + + Consider the following XML configuration for a bean definition: + + + + + + + + The Spring container creates a new instance of the AppPreferences bean by using the appPreferences + bean definition once for the entire web application. That is, the appPreferences bean is scoped at the + ServletContext level and stored as a regular ServletContext attribute. This is somewhat similar to a + Spring singleton bean but differs in two important ways: It is a singleton per ServletContext, not per + Spring ApplicationContext (for which there may be several in any given web application), and it is + actually exposed and therefore visible as a ServletContext attribute. + + + When using annotation-driven components or Java configuration, you can use the + @ApplicationScope annotation to assign a component to the application scope. The following + example shows how to do so: + + + Java + + + @ApplicationScope + @Component + public class AppPreferences { +   // ... + } + + + + Kotlin + + + @ApplicationScope + @Component + class AppPreferences { +   // ... + } + + + + + WebSocket Scope + + WebSocket scope is associated with the lifecycle of a WebSocket session and applies to STOMP over + WebSocket applications, see WebSocket scope for more details. + + Scoped Beans as Dependencies + + The Spring IoC container manages not only the instantiation of your objects (beans), but also the + wiring up of collaborators (or dependencies). If you want to inject (for example) an HTTP request- + scoped bean into another bean of a longer-lived scope, you may choose to inject an AOP proxy in + place of the scoped bean. That is, you need to inject a proxy object that exposes the same public + interface as the scoped object but that can also retrieve the real target object from the relevant + scope (such as an HTTP request) and delegate method calls onto the real object. + + + You may also use between beans that are scoped as singleton, + with the reference then going through an intermediate proxy that is serializable + and therefore able to re-obtain the target singleton bean on deserialization. + + + When declaring against a bean of scope prototype, every + method call on the shared proxy leads to the creation of a new target instance to + which the call is then being forwarded. + + Also, scoped proxies are not the only way to access beans from shorter scopes in a + lifecycle-safe fashion. You may also declare your injection point (that is, the +  constructor or setter argument or autowired field) as ObjectFactory, + allowing for a getObject() call to retrieve the current instance on demand every + time it is needed — without holding on to the instance or storing it separately. + + + As an extended variant, you may declare ObjectProvider which + delivers several additional access variants, including getIfAvailable and + getIfUnique. + + + The JSR-330 variant of this is called Provider and is used with a + Provider declaration and a corresponding get() call for every + retrieval attempt. See here for more details on JSR-330 overall. + + + The configuration in the following example is only one line, but it is important to understand the + “why” as well as the “how” behind it: + + + + + +   +   +   +   ① +   + + +   +   +   +   +   + + + + ① The line that defines the proxy. + + To create such a proxy, you insert a child element into a scoped bean definition + (see Choosing the Type of Proxy to Create and XML Schema-based configuration). Why do + definitions of beans scoped at the request, session and custom-scope levels require the element? Consider the following singleton bean definition and contrast it with what you + need to define for the aforementioned scopes (note that the following userPreferences bean + definition as it stands is incomplete): + + + + + + + +   + + + + + In the preceding example, the singleton bean (userManager) is injected with a reference to the HTTP + Session-scoped bean (userPreferences). The salient point here is that the userManager bean is a + singleton: it is instantiated exactly once per container, and its dependencies (in this case only one, + the userPreferences bean) are also injected only once. This means that the userManager bean + operates only on the exact same userPreferences object (that is, the one with which it was originally + injected). + + This is not the behavior you want when injecting a shorter-lived scoped bean into a longer-lived + scoped bean (for example, injecting an HTTP Session-scoped collaborating bean as a dependency + into singleton bean). Rather, you need a single userManager object, and, for the lifetime of an HTTP + Session, you need a userPreferences object that is specific to the HTTP Session. Thus, the container + + creates an object that exposes the exact same public interface as the UserPreferences class (ideally + an object that is a UserPreferences instance), which can fetch the real UserPreferences object from + the scoping mechanism (HTTP request, Session, and so forth). The container injects this proxy + object into the userManager bean, which is unaware that this UserPreferences reference is a proxy. In + this example, when a UserManager instance invokes a method on the dependency-injected + UserPreferences object, it is actually invoking a method on the proxy. The proxy then fetches the + real UserPreferences object from (in this case) the HTTP Session and delegates the method + invocation onto the retrieved real UserPreferences object. + + Thus, you need the following (correct and complete) configuration when injecting request- and + session-scoped beans into collaborating objects, as the following example shows: + + + + +   + + + + +   + + + + + + Choosing the Type of Proxy to Create + + By default, when the Spring container creates a proxy for a bean that is marked up with the + element, a CGLIB-based class proxy is created. + + + CGLIB proxies intercept only public method calls! Do not call non-public methods +  on such a proxy. They are not delegated to the actual scoped target object. + + + Alternatively, you can configure the Spring container to create standard JDK interface-based + proxies for such scoped beans, by specifying false for the value of the proxy-target-class attribute + of the element. Using JDK interface-based proxies means that you do not need + additional libraries in your application classpath to affect such proxying. However, it also means + that the class of the scoped bean must implement at least one interface and that all collaborators + into which the scoped bean is injected must reference the bean through one of its interfaces. The + following example shows a proxy based on an interface: + + + + + +   + + + + +   + + + + + For more detailed information about choosing class-based or interface-based proxying, see + Proxying Mechanisms. + + Custom Scopes + + The bean scoping mechanism is extensible. You can define your own scopes or even redefine + existing scopes, although the latter is considered bad practice and you cannot override the built-in + singleton and prototype scopes. + + + + Creating a Custom Scope + + To integrate your custom scopes into the Spring container, you need to implement the + org.springframework.beans.factory.config.Scope interface, which is described in this section. For an + idea of how to implement your own scopes, see the Scope implementations that are supplied with + the Spring Framework itself and the Scope javadoc, which explains the methods you need to + implement in more detail. + + + The Scope interface has four methods to get objects from the scope, remove them from the scope, + and let them be destroyed. + + + The session scope implementation, for example, returns the session-scoped bean (if it does not + exist, the method returns a new instance of the bean, after having bound it to the session for future + reference). The following method returns the object from the underlying scope: + + + Java + + + Object get(String name, ObjectFactory objectFactory) + + + + Kotlin + + + fun get(name: String, objectFactory: ObjectFactory<*>): Any + + + + The session scope implementation, for example, removes the session-scoped bean from the + underlying session. The object should be returned, but you can return null if the object with the + specified name is not found. The following method removes the object from the underlying scope: + + + Java + + + Object remove(String name) + + + + Kotlin + + + fun remove(name: String): Any + + + + The following method registers a callback that the scope should invoke when it is destroyed or + when the specified object in the scope is destroyed: + + + Java + + + void registerDestructionCallback(String name, Runnable destructionCallback) + + Kotlin + + + fun registerDestructionCallback(name: String, destructionCallback: Runnable) + + + + See the javadoc or a Spring scope implementation for more information on destruction callbacks. + + The following method obtains the conversation identifier for the underlying scope: + + + Java + + + String getConversationId() + + + + Kotlin + + + fun getConversationId(): String + + + + This identifier is different for each scope. For a session scoped implementation, this identifier can + be the session identifier. + + + + Using a Custom Scope + + After you write and test one or more custom Scope implementations, you need to make the Spring + container aware of your new scopes. The following method is the central method to register a new + Scope with the Spring container: + + + Java + + + void registerScope(String scopeName, Scope scope); + + + + Kotlin + + + fun registerScope(scopeName: String, scope: Scope) + + + + This method is declared on the ConfigurableBeanFactory interface, which is available through the + BeanFactory property on most of the concrete ApplicationContext implementations that ship with + Spring. + + + The first argument to the registerScope(..) method is the unique name associated with a scope. + Examples of such names in the Spring container itself are singleton and prototype. The second + argument to the registerScope(..) method is an actual instance of the custom Scope + implementation that you wish to register and use. + + Suppose that you write your custom Scope implementation, and then register it as shown in the + next example. + + The next example uses SimpleThreadScope, which is included with Spring but is not +  registered by default. The instructions would be the same for your own custom + Scope implementations. + + + Java + + + Scope threadScope = new SimpleThreadScope(); + beanFactory.registerScope("thread", threadScope); + + + + Kotlin + + + val threadScope = SimpleThreadScope() + beanFactory.registerScope("thread", threadScope) + + + + You can then create bean definitions that adhere to the scoping rules of your custom Scope, as + follows: + + + + + + + + With a custom Scope implementation, you are not limited to programmatic registration of the scope. + You can also do the Scope registration declaratively, by using the CustomScopeConfigurer class, as the + following example shows: + + + + + +   +   +   +   +   +   +   +   +   + + +   +   +   +   + + +   +   +   + + + + + + + + When you place within a declaration for a FactoryBean +  implementation, it is the factory bean itself that is scoped, not the object returned + from getObject(). + + + 2.1.6. Customizing the Nature of a Bean + + The Spring Framework provides a number of interfaces you can use to customize the nature of a + bean. This section groups them as follows: + + • Lifecycle Callbacks + + • ApplicationContextAware and BeanNameAware + + • Other Aware Interfaces + + + Lifecycle Callbacks + + To interact with the container’s management of the bean lifecycle, you can implement the Spring + InitializingBean and DisposableBean interfaces. The container calls afterPropertiesSet() for the + + former and destroy() for the latter to let the bean perform certain actions upon initialization and + destruction of your beans. + + + The JSR-250 @PostConstruct and @PreDestroy annotations are generally considered + best practice for receiving lifecycle callbacks in a modern Spring application. Using + these annotations means that your beans are not coupled to Spring-specific +  interfaces. For details, see Using @PostConstruct and @PreDestroy. + + + If you do not want to use the JSR-250 annotations but you still want to remove + coupling, consider init-method and destroy-method bean definition metadata. + + + Internally, the Spring Framework uses BeanPostProcessor implementations to process any callback + interfaces it can find and call the appropriate methods. If you need custom features or other + lifecycle behavior Spring does not by default offer, you can implement a BeanPostProcessor yourself. + For more information, see Container Extension Points. + + + In addition to the initialization and destruction callbacks, Spring-managed objects may also + implement the Lifecycle interface so that those objects can participate in the startup and shutdown + process, as driven by the container’s own lifecycle. + + + The lifecycle callback interfaces are described in this section. + + + + Initialization Callbacks + + The org.springframework.beans.factory.InitializingBean interface lets a bean perform + initialization work after the container has set all necessary properties on the bean. The + InitializingBean interface specifies a single method: + + + + void afterPropertiesSet() throws Exception; + + + + We recommend that you do not use the InitializingBean interface, because it unnecessarily couples + the code to Spring. Alternatively, we suggest using the @PostConstruct annotation or specifying a + POJO initialization method. In the case of XML-based configuration metadata, you can use the init- + method attribute to specify the name of the method that has a void no-argument signature. With + Java configuration, you can use the initMethod attribute of @Bean. See Receiving Lifecycle Callbacks. + Consider the following example: + + + + + + + + Java + + + public class ExampleBean { + + +   public void init() { +   // do some initialization work +   } + } + + Kotlin + + + class ExampleBean { + + +   fun init() { +   // do some initialization work +   } + } + + + + The preceding example has almost exactly the same effect as the following example (which consists + of two listings): + + + + + + + + Java + + + public class AnotherExampleBean implements InitializingBean { + + +   @Override +   public void afterPropertiesSet() { +   // do some initialization work +   } + } + + + + Kotlin + + + class AnotherExampleBean : InitializingBean { + + +   override fun afterPropertiesSet() { +   // do some initialization work +   } + } + + + + However, the first of the two preceding examples does not couple the code to Spring. + + + + Destruction Callbacks + + Implementing the org.springframework.beans.factory.DisposableBean interface lets a bean get a + callback when the container that contains it is destroyed. The DisposableBean interface specifies a + single method: + + + + void destroy() throws Exception; + + + + We recommend that you do not use the DisposableBean callback interface, because it unnecessarily + couples the code to Spring. Alternatively, we suggest using the @PreDestroy annotation or specifying + a generic method that is supported by bean definitions. With XML-based configuration metadata, + you can use the destroy-method attribute on the . With Java configuration, you can use the + + destroyMethod attribute of @Bean. See Receiving Lifecycle Callbacks. Consider the following + definition: + + + + + + + + Java + + + public class ExampleBean { + + +   public void cleanup() { +   // do some destruction work (like releasing pooled connections) +   } + } + + + + Kotlin + + + class ExampleBean { + + +   fun cleanup() { +   // do some destruction work (like releasing pooled connections) +   } + } + + + + The preceding definition has almost exactly the same effect as the following definition: + + + + + + + + Java + + + public class AnotherExampleBean implements DisposableBean { + + +   @Override +   public void destroy() { +   // do some destruction work (like releasing pooled connections) +   } + } + + + + Kotlin + + + class AnotherExampleBean : DisposableBean { + + +   override fun destroy() { +   // do some destruction work (like releasing pooled connections) +   } + } + + However, the first of the two preceding definitions does not couple the code to Spring. + + + You can assign the destroy-method attribute of a element a special (inferred) + value, which instructs Spring to automatically detect a public close or shutdown + method on the specific bean class. (Any class that implements + java.lang.AutoCloseable or java.io.Closeable would therefore match.) You can +  also set this special (inferred) value on the default-destroy-method attribute of a + element to apply this behavior to an entire set of beans (see Default + Initialization and Destroy Methods). Note that this is the default behavior with Java + configuration. + + + + Default Initialization and Destroy Methods + + When you write initialization and destroy method callbacks that do not use the Spring-specific + InitializingBean and DisposableBean callback interfaces, you typically write methods with names + such as init(), initialize(), dispose(), and so on. Ideally, the names of such lifecycle callback + methods are standardized across a project so that all developers use the same method names and + ensure consistency. + + + You can configure the Spring container to “look” for named initialization and destroy callback + method names on every bean. This means that you, as an application developer, can write your + application classes and use an initialization callback called init(), without having to configure an + init-method="init" attribute with each bean definition. The Spring IoC container calls that method + when the bean is created (and in accordance with the standard lifecycle callback contract described + previously). This feature also enforces a consistent naming convention for initialization and destroy + method callbacks. + + Suppose that your initialization callback methods are named init() and your destroy callback + methods are named destroy(). Your class then resembles the class in the following example: + + + Java + + + public class DefaultBlogService implements BlogService { + + +   private BlogDao blogDao; + + +   public void setBlogDao(BlogDao blogDao) { +   this.blogDao = blogDao; +   } + + +   // this is (unsurprisingly) the initialization callback method +   public void init() { +   if (this.blogDao == null) { +   throw new IllegalStateException("The [blogDao] property must be set."); +   } +   } + } + + Kotlin + + + class DefaultBlogService : BlogService { + + +   private var blogDao: BlogDao? = null + + +   // this is (unsurprisingly) the initialization callback method +   fun init() { +   if (blogDao == null) { +   throw IllegalStateException("The [blogDao] property must be set.") +   } +   } + } + + + + You could then use that class in a bean resembling the following: + + + + + + +   +   +   + + + + + + + The presence of the default-init-method attribute on the top-level element attribute causes + the Spring IoC container to recognize a method called init on the bean class as the initialization + method callback. When a bean is created and assembled, if the bean class has such a method, it is + invoked at the appropriate time. + + + You can configure destroy method callbacks similarly (in XML, that is) by using the default- + destroy-method attribute on the top-level element. + + + Where existing bean classes already have callback methods that are named at variance with the + convention, you can override the default by specifying (in XML, that is) the method name by using + the init-method and destroy-method attributes of the itself. + + + The Spring container guarantees that a configured initialization callback is called immediately after + a bean is supplied with all dependencies. Thus, the initialization callback is called on the raw bean + reference, which means that AOP interceptors and so forth are not yet applied to the bean. A target + bean is fully created first and then an AOP proxy (for example) with its interceptor chain is applied. + If the target bean and the proxy are defined separately, your code can even interact with the raw + target bean, bypassing the proxy. Hence, it would be inconsistent to apply the interceptors to the + init method, because doing so would couple the lifecycle of the target bean to its proxy or + interceptors and leave strange semantics when your code interacts directly with the raw target + bean. \ No newline at end of file diff --git a/spring-ai-core/pom.xml b/spring-ai-core/pom.xml index 53f9ea835..9e3d72604 100644 --- a/spring-ai-core/pom.xml +++ b/spring-ai-core/pom.xml @@ -38,6 +38,24 @@ + + org.springframework.ai + spring-ai-commons + ${project.version} + + + + org.springframework.ai + spring-ai-vector-store + ${project.version} + + + + org.springframework.ai + spring-ai-model + ${project.version} + + com.fasterxml.jackson.module jackson-module-jsonSchema @@ -165,35 +183,7 @@ - - antlr4 - - false - - - - - org.antlr - antlr4-maven-plugin - ${antlr.version} - - ${basedir}/src/main/resources/antlr4 - ${basedir}/src/main/java - - true - - - - - antlr4 - - - - - - - + diff --git a/spring-ai-model/pom.xml b/spring-ai-model/pom.xml new file mode 100644 index 000000000..9d42a3b40 --- /dev/null +++ b/spring-ai-model/pom.xml @@ -0,0 +1,128 @@ + + + + + 4.0.0 + + org.springframework.ai + spring-ai + 1.0.0-SNAPSHOT + + spring-ai-model + jar + Spring AI Model + Core model interfaces and classes for Spring AI + https://github.com/spring-projects/spring-ai + + + https://github.com/spring-projects/spring-ai + git://github.com/spring-projects/spring-ai.git + git@github.com:spring-projects/spring-ai.git + + + + 17 + 17 + + + + + org.springframework.ai + spring-ai-commons + ${project.parent.version} + + + + + org.springframework + spring-context + + + + com.fasterxml.jackson.core + jackson-databind + + + + io.micrometer + micrometer-observation + + + + io.micrometer + micrometer-tracing-bridge-otel + true + + + + io.projectreactor + reactor-core + + + + com.github.victools + jsonschema-generator + ${jsonschema.version} + + + + com.github.victools + jsonschema-module-jackson + ${jsonschema.version} + + + + com.github.victools + jsonschema-module-swagger-2 + ${jsonschema.version} + + + + io.swagger.core.v3 + swagger-annotations + ${swagger-annotations.version} + + + + org.jetbrains.kotlin + kotlin-stdlib + true + + + + org.jetbrains.kotlin + kotlin-reflect + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.micrometer + micrometer-observation-test + test + + + + + diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/DefaultUsage.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/metadata/DefaultUsage.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/DefaultUsage.java rename to spring-ai-model/src/main/java/org/springframework/ai/chat/metadata/DefaultUsage.java index e9a812f44..5e6f3190b 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/DefaultUsage.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/metadata/DefaultUsage.java @@ -162,4 +162,4 @@ public class DefaultUsage implements Usage { + ", totalTokens=" + this.totalTokens + '}'; } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/EmptyUsage.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/metadata/EmptyUsage.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/EmptyUsage.java rename to spring-ai-model/src/main/java/org/springframework/ai/chat/metadata/EmptyUsage.java index 5aeefe809..173ccc267 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/EmptyUsage.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/metadata/EmptyUsage.java @@ -42,4 +42,4 @@ public class EmptyUsage implements Usage { return Map.of(); } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/Usage.java b/spring-ai-model/src/main/java/org/springframework/ai/chat/metadata/Usage.java similarity index 99% rename from spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/Usage.java rename to spring-ai-model/src/main/java/org/springframework/ai/chat/metadata/Usage.java index 2afe495d7..4663b275b 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/Usage.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/chat/metadata/Usage.java @@ -65,4 +65,4 @@ public interface Usage { */ Object getNativeUsage(); -} +} \ No newline at end of file diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/AbstractEmbeddingModel.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/AbstractEmbeddingModel.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/AbstractEmbeddingModel.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/AbstractEmbeddingModel.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingModel.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingModel.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingModel.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingModel.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingRequest.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingRequest.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingRequest.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/DocumentEmbeddingRequest.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/Embedding.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/Embedding.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/Embedding.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/Embedding.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingModel.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingModel.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingModel.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingModel.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingOptions.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingOptions.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingOptions.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingOptions.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingOptionsBuilder.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingOptionsBuilder.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingOptionsBuilder.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingOptionsBuilder.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingRequest.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingRequest.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingRequest.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingRequest.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingResponse.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingResponse.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingResponse.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingResponse.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingResponseMetadata.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingResponseMetadata.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingResponseMetadata.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingResponseMetadata.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingResultMetadata.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingResultMetadata.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/EmbeddingResultMetadata.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/EmbeddingResultMetadata.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConvention.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConvention.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConvention.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConvention.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandler.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandler.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandler.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandler.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContext.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContext.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContext.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContext.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationConvention.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationConvention.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationConvention.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationConvention.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationDocumentation.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationDocumentation.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationDocumentation.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationDocumentation.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/package-info.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/package-info.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/observation/package-info.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/observation/package-info.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/package-info.java b/spring-ai-model/src/main/java/org/springframework/ai/embedding/package-info.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/embedding/package-info.java rename to spring-ai-model/src/main/java/org/springframework/ai/embedding/package-info.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/AbstractResponseMetadata.java b/spring-ai-model/src/main/java/org/springframework/ai/model/AbstractResponseMetadata.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/AbstractResponseMetadata.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/AbstractResponseMetadata.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ApiKey.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ApiKey.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ApiKey.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ApiKey.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ChatModelDescription.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ChatModelDescription.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ChatModelDescription.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ChatModelDescription.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/EmbeddingModelDescription.java b/spring-ai-model/src/main/java/org/springframework/ai/model/EmbeddingModelDescription.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/EmbeddingModelDescription.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/EmbeddingModelDescription.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/EmbeddingUtils.java b/spring-ai-model/src/main/java/org/springframework/ai/model/EmbeddingUtils.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/EmbeddingUtils.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/EmbeddingUtils.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/KotlinModule.java b/spring-ai-model/src/main/java/org/springframework/ai/model/KotlinModule.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/KotlinModule.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/KotlinModule.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/Model.java b/spring-ai-model/src/main/java/org/springframework/ai/model/Model.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/Model.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/Model.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ModelDescription.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ModelDescription.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ModelDescription.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ModelDescription.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ModelOptions.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ModelOptions.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ModelOptions.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ModelOptions.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ModelOptionsUtils.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ModelOptionsUtils.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ModelOptionsUtils.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ModelOptionsUtils.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ModelRequest.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ModelRequest.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ModelRequest.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ModelRequest.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ModelResponse.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ModelResponse.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ModelResponse.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ModelResponse.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ModelResult.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ModelResult.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ModelResult.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ModelResult.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/MutableResponseMetadata.java b/spring-ai-model/src/main/java/org/springframework/ai/model/MutableResponseMetadata.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/MutableResponseMetadata.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/MutableResponseMetadata.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/NoopApiKey.java b/spring-ai-model/src/main/java/org/springframework/ai/model/NoopApiKey.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/NoopApiKey.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/NoopApiKey.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ResponseMetadata.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ResponseMetadata.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ResponseMetadata.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ResponseMetadata.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/ResultMetadata.java b/spring-ai-model/src/main/java/org/springframework/ai/model/ResultMetadata.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/ResultMetadata.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/ResultMetadata.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/SimpleApiKey.java b/spring-ai-model/src/main/java/org/springframework/ai/model/SimpleApiKey.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/SimpleApiKey.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/SimpleApiKey.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/SpringAIModelProperties.java b/spring-ai-model/src/main/java/org/springframework/ai/model/SpringAIModelProperties.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/SpringAIModelProperties.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/SpringAIModelProperties.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/SpringAIModels.java b/spring-ai-model/src/main/java/org/springframework/ai/model/SpringAIModels.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/SpringAIModels.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/SpringAIModels.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/StreamingModel.java b/spring-ai-model/src/main/java/org/springframework/ai/model/StreamingModel.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/StreamingModel.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/StreamingModel.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/observation/ErrorLoggingObservationHandler.java b/spring-ai-model/src/main/java/org/springframework/ai/model/observation/ErrorLoggingObservationHandler.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/observation/ErrorLoggingObservationHandler.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/observation/ErrorLoggingObservationHandler.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/observation/ModelObservationContext.java b/spring-ai-model/src/main/java/org/springframework/ai/model/observation/ModelObservationContext.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/observation/ModelObservationContext.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/observation/ModelObservationContext.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/observation/ModelUsageMetricsGenerator.java b/spring-ai-model/src/main/java/org/springframework/ai/model/observation/ModelUsageMetricsGenerator.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/observation/ModelUsageMetricsGenerator.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/observation/ModelUsageMetricsGenerator.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/observation/package-info.java b/spring-ai-model/src/main/java/org/springframework/ai/model/observation/package-info.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/model/observation/package-info.java rename to spring-ai-model/src/main/java/org/springframework/ai/model/observation/package-info.java diff --git a/spring-ai-model/src/main/java/org/springframework/ai/model/package-info.java b/spring-ai-model/src/main/java/org/springframework/ai/model/package-info.java new file mode 100644 index 000000000..207af410e --- /dev/null +++ b/spring-ai-model/src/main/java/org/springframework/ai/model/package-info.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023-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. + */ + +/** + * Provides a set of interfaces and classes for a generic API designed to interact with + * various AI models. This package includes interfaces for handling AI model calls, + * requests, responses, results, and associated metadata. It is designed to offer a + * flexible and adaptable framework for interacting with different types of AI models, + * abstracting the complexities involved in model invocation and result processing. The + * use of generics enhances the API's capability to work with a wide range of models, + * ensuring a broad applicability across diverse AI scenarios. + * + */ + +package org.springframework.ai.model; diff --git a/spring-ai-core/src/main/resources/embedding/embedding-model-dimensions.properties b/spring-ai-model/src/main/resources/embedding/embedding-model-dimensions.properties similarity index 100% rename from spring-ai-core/src/main/resources/embedding/embedding-model-dimensions.properties rename to spring-ai-model/src/main/resources/embedding/embedding-model-dimensions.properties diff --git a/spring-ai-core/src/test/java/org/springframework/ai/chat/metadata/DefaultUsageTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/metadata/DefaultUsageTests.java similarity index 99% rename from spring-ai-core/src/test/java/org/springframework/ai/chat/metadata/DefaultUsageTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/chat/metadata/DefaultUsageTests.java index bf33c530e..0fedfefc3 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/chat/metadata/DefaultUsageTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/metadata/DefaultUsageTests.java @@ -259,4 +259,4 @@ public class DefaultUsageTests { // value } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/test/java/org/springframework/ai/embedding/AbstractEmbeddingModelTests.java b/spring-ai-model/src/test/java/org/springframework/ai/embedding/AbstractEmbeddingModelTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/embedding/AbstractEmbeddingModelTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/embedding/AbstractEmbeddingModelTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConventionTests.java b/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConventionTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConventionTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/DefaultEmbeddingModelObservationConventionTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandlerTests.java b/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandlerTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandlerTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelMeterObservationHandlerTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContextTests.java b/spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContextTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContextTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/embedding/observation/EmbeddingModelObservationContextTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/metadata/UsageTests.java b/spring-ai-model/src/test/java/org/springframework/ai/metadata/UsageTests.java similarity index 99% rename from spring-ai-core/src/test/java/org/springframework/ai/metadata/UsageTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/metadata/UsageTests.java index 72b1c6cc1..287da3476 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/metadata/UsageTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/metadata/UsageTests.java @@ -87,4 +87,4 @@ public class UsageTests { verifyUsage(usage); } -} +} \ No newline at end of file diff --git a/spring-ai-core/src/test/java/org/springframework/ai/model/MediaTests.java b/spring-ai-model/src/test/java/org/springframework/ai/model/MediaTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/model/MediaTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/model/MediaTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/model/ModelOptionsUtilsTests.java b/spring-ai-model/src/test/java/org/springframework/ai/model/ModelOptionsUtilsTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/model/ModelOptionsUtilsTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/model/ModelOptionsUtilsTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/model/observation/ModelObservationContextTests.java b/spring-ai-model/src/test/java/org/springframework/ai/model/observation/ModelObservationContextTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/model/observation/ModelObservationContextTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/model/observation/ModelObservationContextTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/model/observation/ModelUsageMetricsGeneratorTests.java b/spring-ai-model/src/test/java/org/springframework/ai/model/observation/ModelUsageMetricsGeneratorTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/model/observation/ModelUsageMetricsGeneratorTests.java rename to spring-ai-model/src/test/java/org/springframework/ai/model/observation/ModelUsageMetricsGeneratorTests.java diff --git a/spring-ai-vector-store/pom.xml b/spring-ai-vector-store/pom.xml new file mode 100644 index 000000000..2fd9b9d45 --- /dev/null +++ b/spring-ai-vector-store/pom.xml @@ -0,0 +1,122 @@ + + + + + 4.0.0 + + org.springframework.ai + spring-ai + 1.0.0-SNAPSHOT + + spring-ai-vector-store + jar + Spring AI Vector Store + Common vector store functionality for Spring AI + https://github.com/spring-projects/spring-ai + + + https://github.com/spring-projects/spring-ai + git://github.com/spring-projects/spring-ai.git + git@github.com:spring-projects/spring-ai.git + + + + 17 + 17 + + + + + org.springframework.ai + spring-ai-model + ${project.parent.version} + + + + io.micrometer + micrometer-tracing-bridge-otel + true + + + + + + org.antlr + antlr4-runtime + ${antlr.version} + + + + + org.springframework + spring-context + + + + + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.micrometer + micrometer-observation-test + test + + + + + + + antlr4 + + false + + + + + org.antlr + antlr4-maven-plugin + ${antlr.version} + + ${basedir}/src/main/resources/antlr4 + ${basedir}/src/main/java + true + + + + + antlr4 + + + + + + + + + + diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/AbstractVectorStoreBuilder.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/AbstractVectorStoreBuilder.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/AbstractVectorStoreBuilder.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/AbstractVectorStoreBuilder.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SearchRequest.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SearchRequest.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SearchRequest.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SearchRequest.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStore.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStore.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStore.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStore.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreContent.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreContent.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreContent.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreContent.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SpringAIVectorStoreTypes.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SpringAIVectorStoreTypes.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SpringAIVectorStoreTypes.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SpringAIVectorStoreTypes.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/VectorStore.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/VectorStore.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/VectorStore.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/VectorStore.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/Filter.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/Filter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/Filter.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/Filter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilder.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilder.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilder.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilder.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionConverter.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionConverter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionConverter.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionConverter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParser.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParser.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParser.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParser.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/FilterHelper.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterHelper.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/FilterHelper.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterHelper.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/Filters.interp b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/Filters.interp similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/Filters.interp rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/Filters.interp diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseListener.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseListener.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseListener.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseListener.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseVisitor.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseVisitor.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseVisitor.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersBaseVisitor.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.interp b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.interp similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.interp rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.interp diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersLexer.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersListener.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersListener.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersListener.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersListener.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersParser.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersParser.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersParser.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersParser.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersVisitor.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersVisitor.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersVisitor.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/antlr4/FiltersVisitor.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/converter/AbstractFilterExpressionConverter.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/converter/AbstractFilterExpressionConverter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/converter/AbstractFilterExpressionConverter.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/converter/AbstractFilterExpressionConverter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverter.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverter.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/converter/PrintFilterExpressionConverter.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/converter/PrintFilterExpressionConverter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/converter/PrintFilterExpressionConverter.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/converter/PrintFilterExpressionConverter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverter.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverter.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConvention.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConvention.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConvention.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConvention.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContentProcessor.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContentProcessor.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContentProcessor.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContentProcessor.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContext.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContext.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContext.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContext.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationConvention.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationConvention.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationConvention.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationConvention.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationDocumentation.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationDocumentation.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationDocumentation.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationDocumentation.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilter.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilter.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilter.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilter.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandler.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandler.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandler.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandler.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/package-info.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/package-info.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/package-info.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/observation/package-info.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/package-info.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/package-info.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/package-info.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/package-info.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/properties/CommonVectorStoreProperties.java b/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/properties/CommonVectorStoreProperties.java similarity index 100% rename from spring-ai-core/src/main/java/org/springframework/ai/vectorstore/properties/CommonVectorStoreProperties.java rename to spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/properties/CommonVectorStoreProperties.java diff --git a/spring-ai-core/src/main/resources/antlr4/org/springframework/ai/vectorstore/filter/antlr4/Filters.g4 b/spring-ai-vector-store/src/main/resources/antlr4/org/springframework/ai/vectorstore/filter/antlr4/Filters.g4 similarity index 100% rename from spring-ai-core/src/main/resources/antlr4/org/springframework/ai/vectorstore/filter/antlr4/Filters.g4 rename to spring-ai-vector-store/src/main/resources/antlr4/org/springframework/ai/vectorstore/filter/antlr4/Filters.g4 diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreSimilarityTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreSimilarityTests.java similarity index 97% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreSimilarityTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreSimilarityTests.java index 895dee54a..ff293018e 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreSimilarityTests.java +++ b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreSimilarityTests.java @@ -19,7 +19,7 @@ package org.springframework.ai.vectorstore; import java.util.HashMap; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.ai.document.Document; diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreWithFilterTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreWithFilterTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreWithFilterTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreWithFilterTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilderTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilderTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilderTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionBuilderTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParserTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParserTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParserTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParserTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/FilterHelperTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/FilterHelperTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/FilterHelperTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/FilterHelperTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/SearchRequestTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/SearchRequestTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/SearchRequestTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/SearchRequestTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverterTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverterTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverterTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/converter/PineconeFilterExpressionConverterTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverterTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverterTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverterTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/filter/converter/SimpleVectorStoreFilterExpressionConverterTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContextTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContextTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContextTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationContextTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilterTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilterTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilterTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationFilterTests.java diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandlerTests.java b/spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandlerTests.java similarity index 100% rename from spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandlerTests.java rename to spring-ai-vector-store/src/test/java/org/springframework/ai/vectorstore/observation/VectorStoreQueryResponseObservationHandlerTests.java diff --git a/src/checkstyle/checkstyle.xml b/src/checkstyle/checkstyle.xml index bc0daad06..8162ac427 100644 --- a/src/checkstyle/checkstyle.xml +++ b/src/checkstyle/checkstyle.xml @@ -100,7 +100,7 @@ + value="org.springframework.ai.test.vectorstore.ObservationTestUtil.*, org.springframework.ai.autoconfigure.vectorstore.observation.ObservationTestUtil.*, org.awaitility.Awaitility.*, org.springframework.ai.aot.AiRuntimeHints.*, org.springframework.ai.openai.metadata.support.OpenAiApiResponseHeaders.*, org.springframework.ai.image.observation.ImageModelObservationDocumentation.*, org.springframework.ai.observation.embedding.EmbeddingModelObservationDocumentation.*, org.springframework.aot.hint.predicate.RuntimeHintsPredicates.*, org.springframework.ai.vectorstore.filter.Filter.ExpressionType.*, org.springframework.ai.chat.observation.ChatModelObservationDocumentation.*, org.assertj.core.groups.Tuple.*, org.assertj.core.api.AssertionsForClassTypes.*, org.junit.jupiter.api.Assertions.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.mockito.ArgumentMatchers.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*, org.springframework.web.reactive.function.server.RequestPredicates.*, org.springframework.web.reactive.function.server.RouterFunctions.*, org.springframework.test.web.servlet.setup.MockMvcBuilders.*"/>