-
Notifications
You must be signed in to change notification settings - Fork 699
Spring Data 2024.1 Release Notes
-
Revise JPA Query Enhancer
-
Add keyspace qualification for Cassandra tables and user-defined types
-
Add Value Expression support to Repository Query Methods
Details
-
Spring Data Build - 3.4
By default the Spring Data infrastructure only auto-detects fragments, custom extensions to a repository interface, within the repositories base-package. Therefore, fragments residing in another location or contributed by an external archive will not be found if they do not share a common namespace.
New in 3.4, spring.factories allows you to circumvent this restriction by providing both, fragment interface and implementation data as outlined in the following example.
package com.acme.search;
public interface SearchExtension<T> {
List<T> search(String text, Limit limit);
}
class DefaultSearchExtension<T> implements SearchExtension<T> {
// ...
}com.acme.search.SearchExtension=com.acme.search.DefaultSearchExtensionpackage io.my.movies;
interface MovieRepository extends CrudRepository<Movie, String>, SearchExtension<Movie> {
}With this change, we also disabled invocation metadata by default as the majority of users doesn’t require metadata and so we improve our resource usage. If you require ExposeInvocationInterceptor.currentInvocation() metadata, then you can selectively enable it on a per-repository basis by post-processing RepositoryFactoryBeanSupport. Setting RepositoryFactoryBeanSupport.setExposeMetadata(true) will expose invocation metadata.
We expanded Value Expression support (general support introduced earlier in 2024.0) to Repository Query methods. You can now leverage property-placeholders in Query methods annotated with @Query.
SQL and JPQL query parsers were refined for an enhanced QueryRenderer model. Also, the internal organization was refactored to decouple query introspection from actual query rewriting. While there is no change in behavior we were able to reduce parsing overhead significantly.
We removed a considerable amount of deprecated API.
BasicJdbcConverter
BatchJdbcOperations
EntityRowMapper(PersistentPropertyPathExtension path, JdbcConverter converter, Identifier identifier)
InsertStrategyFactory(NamedParameterJdbcOperations namedParameterJdbcOperations, BatchJdbcOperations batchJdbcOperations, Dialect dialect)
JdbcConverter.mapRow
JdbcIdentifierBuilder.forBackReferences(JdbcConverter converter, PersistentPropertyPathExtension path, @Nullable Object value)
JdbcIdentifierBuilder.withQualifier(PersistentPropertyPathExtension path, Object value)
QueryMapper(Dialect dialect, JdbcConverter converter)
SqlParametersFactory(RelationalMappingContext context, JdbcConverter converter, Dialect dialect)
JdbcAggregateOperations.delete(T aggregateRoot, Class<T> domainType)
JdbcAggregateOperations.deleteAll(Iterable<? extends T> aggregateRoots, Class<T> domainType)
MyBatisDataAccessStrategy(SqlSession sqlSession, IdentifierProcessing identifierProcessing)
AbstractJdbcQuery.getQueryExecution(JdbcQueryMethod queryMethod, @Nullable ResultSetExtractor<?> extractor, RowMapper<?> rowMapper)StatementMapper.getProjectedFields()
QueryMapper.getMappedObject(Sort sort, @Nullable RelationalPersistentEntity<?> entity)
QueryMapper.getMappedObject(BindMarkers markers, Criteria criteria, Table table, @Nullable RelationalPersistentEntity<?> entity)BasicRelationalConverter
MappingRelationalConverter.createInstance(PersistentEntity<T, RelationalPersistentProperty> entity, Function<Parameter<?, RelationalPersistentProperty>, Object> parameterValueProvider)
RelationalConverter.createInstance(PersistentEntity<T, RelationalPersistentProperty> entity, Function<Parameter<?, RelationalPersistentProperty>, Object> parameterValueProvider)
BasicRelationalPersistentProperty(Property property, PersistentEntity<?, RelationalPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder, RelationalMappingContext context)
BasicRelationalPersistentProperty.getReverseColumnName(PersistentPropertyPathExtension path)
CachingNamingStrategy.getReverseColumnName(PersistentPropertyPathExtension path)
DefaultNamingStrategy.getReverseColumnName(PersistentPropertyPathExtension path)
DefaultNamingStrategy.INSTANCE
NamingStrategy.getReverseColumnName(PersistentPropertyPathExtension path)
DerivedSqlIdentifier.getReference(IdentifierProcessing processing)
EmbeddedRelationalPersistentProperty.getReverseColumnName(PersistentPropertyPathExtension path)
PersistentPropertyPathExtension
RelationalPersistentProperty.getReverseColumnName(PersistentPropertyPathExtension path)
CompositeSqlIdentifier.getReference(IdentifierProcessing processing)
DefaultSqlIdentifier.getReference(IdentifierProcessing processing)
SqlIdentifier.getReference(IdentifierProcessing processing)Leverage the @TimeSeries#expireAfter option to have MongoDB automatically remove expired buckets.
The attribute allows different duration formats like 10s, 3h,… as well as expression (#{@mySpringBean.timeout}) and property placeholder (${my.property.timeout}) syntax.
@Table and @UserDefinedType now accept a keyspace attribute to use a different keyspace than the CQL session keyspace when interacting with these without the need for intermediate USE <keyspace> statements. This feature can leave the CQL session in the configured keyspace and eliminates the need to run multiple CQL sessions while your application accesses data from a different keyspace.
Additionally, you can configure a KeyspaceProvider for StatementFactory that is used with CassandraTemplate and its asynchronous and reactive variants.
CassandraTemplate template = …;
template.getStatementFactory().setKeyspaceProvider((entity, tableName) -> …);KeyspaceProvider by default uses the keyspace configured in CassandraPersistentEntity which represents the model of @Table and @UserDefinedType classes.
We introduced SpecificationBuilder and CqlGenerator as entry points for easier CQL specification discoverability. Previously, specifications were loosely coupled in the specification package. Code that wanted to generate CQL from specifications had to look up the appropriate CQL generator and use it with the specification.
This is much easier now:
CqlSpecification createKeyspace = SpecificationBuilder.createKeyspace("my_keyspace")
.with(KeyspaceOption.REPLICATION, KeyspaceAttributes.newSimpleReplication())
.with(KeyspaceOption.DURABLE_WRITES, true);
// results in CREATE KEYSPACE my_keyspace WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true
String cql = CqlGenerator.toCql(createKeyspace);
CreateTableSpecification createTable = CreateTableSpecification.createTable("my_table")
.partitionKeyColumn("last_name", DataTypes.TEXT)
.partitionKeyColumn("first_name", DataTypes.TEXT)
.column("age", DataTypes.INT);
// results in CREATE TABLE my_table (last_name text, first_name text, age int, PRIMARY KEY(last_name, first_name))
String cql = CqlGenerator.toCql(createTable);Jedis scripting commands (EVAL/EVSALSHA and SCRIPT …) can not be used in transactions and pipelining. This restriction was rooted in missing proper Lua support in early Jedis versions.
With this revision, we deprecate our own MicrometerTracingAdapter and support classes as the Micrometer integration in Lettuce has already been established for several versions. Use Lettuce’s io.lettuce.core.tracing.MicrometerTracing implementation instead of MicrometerTracingAdapter.
The deprecated integration will be removed with the next major revision.
We introduced a customization mechanism for Jedis to apply customizations to JedisClientConfig. You can register a customizer through JedisClientConfigurationBuilder.customize(…) as shown in the following example:
JedisClientConfiguration.builder()
.customize(builder -> {
builder.resp3()
.clientSetInfoConfig(new ClientSetInfoConfig("spring"));
}).build();-
M1 - Sept 13, 2024
-
RC - Oct 18, 2024
-
GA - Nov 15, 2024
-
OSS Support until: Nov 2025
-
End of Life: Feb 2027