Skip to content

Commit d275513

Browse files
onobcmp911de
authored andcommitted
Add support for RepositoryFragmentsContributor.
This change adopts the newly added AOT changes from spring-projects/spring-data-commons#3282 to Cassandra repositories. - Introduces repository fragments contributor and updates the repository factories and factory beans w/ to use the default implementations. - Also makes the `CassandraRepositoryFactoryBean` consistent with its reactive counterpart by only setting the mapping context from the `CassandraOperations` in `afterPropertiesSet` iff the mapping context was not specified by the user. Closes #1574
1 parent ccc0924 commit d275513

12 files changed

+604
-6
lines changed

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/CassandraRepositoryConfigurationExtension.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.data.cassandra.core.mapping.Table;
2626
import org.springframework.data.cassandra.repository.CassandraRepository;
2727
import org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean;
28+
import org.springframework.data.cassandra.repository.support.SimpleCassandraRepository;
2829
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
2930
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
3031
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
@@ -40,6 +41,7 @@
4041
* @author Mark Paluch
4142
* @author Christoph Strobl
4243
* @author Mateusz Szymczak
44+
* @author Chris Bono
4345
*/
4446
public class CassandraRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
4547

@@ -55,6 +57,11 @@ protected String getModulePrefix() {
5557
return "cassandra";
5658
}
5759

60+
@Override
61+
public String getRepositoryBaseClassName() {
62+
return SimpleCassandraRepository.class.getName();
63+
}
64+
5865
@Override
5966
public String getRepositoryFactoryBeanClassName() {
6067
return CassandraRepositoryFactoryBean.class.getName();

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/ReactiveCassandraRepositoryConfigurationExtension.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2222
import org.springframework.data.cassandra.repository.ReactiveCassandraRepository;
2323
import org.springframework.data.cassandra.repository.support.ReactiveCassandraRepositoryFactoryBean;
24+
import org.springframework.data.cassandra.repository.support.SimpleReactiveCassandraRepository;
2425
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
2526
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
2627
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -30,6 +31,7 @@
3031
* {@link RepositoryConfigurationExtension} for Cassandra.
3132
*
3233
* @author Mark Paluch
34+
* @author Chris Bono
3335
* @since 2.0
3436
*/
3537
public class ReactiveCassandraRepositoryConfigurationExtension extends CassandraRepositoryConfigurationExtension {
@@ -39,6 +41,11 @@ public String getModuleName() {
3941
return "Reactive Cassandra";
4042
}
4143

44+
@Override
45+
public String getRepositoryBaseClassName() {
46+
return SimpleReactiveCassandraRepository.class.getName();
47+
}
48+
4249
@Override
4350
public String getRepositoryFactoryBeanClassName() {
4451
return ReactiveCassandraRepositoryFactoryBean.class.getName();

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactory.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.data.repository.core.NamedQueries;
3535
import org.springframework.data.repository.core.RepositoryInformation;
3636
import org.springframework.data.repository.core.RepositoryMetadata;
37+
import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments;
3738
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
3839
import org.springframework.data.repository.query.CachingValueExpressionDelegate;
3940
import org.springframework.data.repository.query.QueryLookupStrategy;
@@ -50,13 +51,16 @@
5051
* @author Thomas Darimont
5152
* @author Mark Paluch
5253
* @author John Blum
54+
* @author Chris Bono
5355
*/
5456
public class CassandraRepositoryFactory extends RepositoryFactorySupport {
5557

5658
private final MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext;
5759

5860
private final CassandraOperations operations;
5961

62+
private CassandraRepositoryFragmentsContributor fragmentsContributor = CassandraRepositoryFragmentsContributor.DEFAULT;
63+
6064
/**
6165
* Create a new {@link CassandraRepositoryFactory} with the given {@link CassandraOperations}.
6266
*
@@ -70,6 +74,17 @@ public CassandraRepositoryFactory(CassandraOperations operations) {
7074
this.mappingContext = operations.getConverter().getMappingContext();
7175
}
7276

77+
/**
78+
* Configures the {@link CassandraRepositoryFragmentsContributor} to be used. Defaults to
79+
* {@link CassandraRepositoryFragmentsContributor#DEFAULT}.
80+
*
81+
* @param fragmentsContributor
82+
* @since 5.0
83+
*/
84+
public void setFragmentsContributor(CassandraRepositoryFragmentsContributor fragmentsContributor) {
85+
this.fragmentsContributor = fragmentsContributor;
86+
}
87+
7388
@Override
7489
protected ProjectionFactory getProjectionFactory(@Nullable ClassLoader classLoader,
7590
@Nullable BeanFactory beanFactory) {
@@ -103,6 +118,23 @@ protected Optional<QueryLookupStrategy> getQueryLookupStrategy(@Nullable Key key
103118
new CachingValueExpressionDelegate(valueExpressionDelegate), mappingContext));
104119
}
105120

121+
@Override
122+
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
123+
return getRepositoryFragments(metadata, operations);
124+
}
125+
126+
/**
127+
* Creates {@link RepositoryFragments} based on {@link RepositoryMetadata} to add Cassandra-specific extensions.
128+
* Built-in fragment contribution can be customized by configuring {@link CassandraRepositoryFragmentsContributor}.
129+
*
130+
* @param metadata repository metadata.
131+
* @param operations the Cassandra operations manager.
132+
* @return {@link RepositoryFragments} to be added to the repository.
133+
* @since 5.0
134+
*/
135+
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata, CassandraOperations operations) {
136+
return fragmentsContributor.contribute(metadata, getEntityInformation(metadata.getDomainType()), operations);
137+
}
106138

107139
private record CassandraQueryLookupStrategy(CassandraOperations operations,
108140
ValueExpressionDelegate valueExpressionDelegate,
@@ -130,4 +162,3 @@ public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata,
130162
}
131163

132164
}
133-

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryBean.java

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.data.cassandra.core.CassandraOperations;
2020
import org.springframework.data.cassandra.core.CassandraTemplate;
2121
import org.springframework.data.cassandra.repository.CassandraRepository;
22+
import org.springframework.data.mapping.context.MappingContext;
2223
import org.springframework.data.repository.Repository;
2324
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
2425
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
@@ -31,12 +32,17 @@
3132
* @author John Blum
3233
* @author Oliver Gierke
3334
* @author Mark Paluch
35+
* @author Chris Bono
3436
*/
3537
public class CassandraRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
3638
extends RepositoryFactoryBeanSupport<T, S, ID> {
3739

40+
private boolean mappingContextConfigured = false;
41+
3842
private @Nullable CassandraOperations cassandraOperations;
3943

44+
private CassandraRepositoryFragmentsContributor repositoryFragmentsContributor = CassandraRepositoryFragmentsContributor.DEFAULT;
45+
4046
/**
4147
* Create a new {@link CassandraRepositoryFactoryBean} for the given repository interface.
4248
*
@@ -51,7 +57,35 @@ protected RepositoryFactorySupport createRepositoryFactory() {
5157

5258
Assert.state(cassandraOperations != null, "CassandraOperations must not be null");
5359

54-
return new CassandraRepositoryFactory(cassandraOperations);
60+
CassandraRepositoryFactory factory = getFactoryInstance(cassandraOperations);
61+
factory.setFragmentsContributor(repositoryFragmentsContributor);
62+
return factory;
63+
}
64+
65+
/**
66+
* Creates and initializes a {@link CassandraRepositoryFactory} instance.
67+
*
68+
* @param operations the Cassandra operations
69+
* @return new {@link CassandraRepositoryFactory} instance
70+
*/
71+
protected CassandraRepositoryFactory getFactoryInstance(CassandraOperations operations) {
72+
return new CassandraRepositoryFactory(operations);
73+
}
74+
75+
@Override
76+
public CassandraRepositoryFragmentsContributor getRepositoryFragmentsContributor() {
77+
return this.repositoryFragmentsContributor;
78+
}
79+
80+
/**
81+
* Configures the {@link CassandraRepositoryFragmentsContributor} to contribute built-in fragment functionality to the
82+
* repository.
83+
*
84+
* @param repositoryFragmentsContributor must not be {@literal null}.
85+
* @since 5.0
86+
*/
87+
public void setRepositoryFragmentsContributor(CassandraRepositoryFragmentsContributor repositoryFragmentsContributor) {
88+
this.repositoryFragmentsContributor = repositoryFragmentsContributor;
5589
}
5690

5791
/**
@@ -61,9 +95,15 @@ protected RepositoryFactorySupport createRepositoryFactory() {
6195
* on Apache Cassandra.
6296
*/
6397
public void setCassandraTemplate(CassandraTemplate cassandraTemplate) {
64-
6598
this.cassandraOperations = cassandraTemplate;
66-
setMappingContext(cassandraTemplate.getConverter().getMappingContext());
99+
}
100+
101+
@Override
102+
protected void setMappingContext(MappingContext<?, ?> mappingContext) {
103+
104+
super.setMappingContext(mappingContext);
105+
106+
this.mappingContextConfigured = true;
67107
}
68108

69109
@Override
@@ -72,5 +112,9 @@ public void afterPropertiesSet() {
72112
super.afterPropertiesSet();
73113

74114
Assert.notNull(cassandraOperations, "CassandraOperations must not be null");
115+
116+
if (!mappingContextConfigured) {
117+
setMappingContext(cassandraOperations.getConverter().getMappingContext());
118+
}
75119
}
76120
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.cassandra.repository.support;
17+
18+
import org.springframework.data.cassandra.core.CassandraOperations;
19+
import org.springframework.data.cassandra.repository.query.CassandraEntityInformation;
20+
import org.springframework.data.repository.core.RepositoryMetadata;
21+
import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments;
22+
import org.springframework.data.repository.core.support.RepositoryFragmentsContributor;
23+
import org.springframework.util.Assert;
24+
25+
/**
26+
* Cassandra-specific {@link RepositoryFragmentsContributor} contributing fragments based on the repository.
27+
* <p>
28+
* Implementations must define a no-args constructor.
29+
*
30+
* @author Chris Bono
31+
* @since 5.0
32+
*/
33+
public interface CassandraRepositoryFragmentsContributor extends RepositoryFragmentsContributor {
34+
35+
CassandraRepositoryFragmentsContributor DEFAULT = EmptyFragmentsContributor.INSTANCE;
36+
37+
/**
38+
* Returns a composed {@code CassandraRepositoryFragmentsContributor} that first applies this contributor to its inputs,
39+
* and then applies the {@code after} contributor concatenating effectively both results. If evaluation of either
40+
* contributors throws an exception, it is relayed to the caller of the composed contributor.
41+
*
42+
* @param after the contributor to apply after this contributor is applied.
43+
* @return a composed contributor that first applies this contributor and then applies the {@code after} contributor.
44+
*/
45+
default CassandraRepositoryFragmentsContributor andThen(CassandraRepositoryFragmentsContributor after) {
46+
47+
Assert.notNull(after, "CassandraRepositoryFragmentsContributor must not be null");
48+
49+
return new CassandraRepositoryFragmentsContributor() {
50+
51+
@Override
52+
public RepositoryFragments contribute(RepositoryMetadata metadata,
53+
CassandraEntityInformation<?, ?> entityInformation, CassandraOperations operations) {
54+
return CassandraRepositoryFragmentsContributor.this.contribute(metadata, entityInformation, operations)
55+
.append(after.contribute(metadata, entityInformation, operations));
56+
}
57+
58+
@Override
59+
public RepositoryFragments describe(RepositoryMetadata metadata) {
60+
return CassandraRepositoryFragmentsContributor.this.describe(metadata).append(after.describe(metadata));
61+
}
62+
};
63+
}
64+
65+
/**
66+
* Creates {@link RepositoryFragments} based on {@link RepositoryMetadata} to add
67+
* Cassandra-specific extensions.
68+
*
69+
* @param metadata repository metadata.
70+
* @param entityInformation must not be {@literal null}.
71+
* @param operations must not be {@literal null}.
72+
* @return {@link RepositoryFragments} to be added to the repository.
73+
*/
74+
RepositoryFragments contribute(RepositoryMetadata metadata,
75+
CassandraEntityInformation<?, ?> entityInformation, CassandraOperations operations);
76+
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.cassandra.repository.support;
17+
18+
import org.springframework.data.cassandra.core.CassandraOperations;
19+
import org.springframework.data.cassandra.repository.query.CassandraEntityInformation;
20+
import org.springframework.data.repository.core.RepositoryMetadata;
21+
import org.springframework.data.repository.core.support.RepositoryComposition;
22+
23+
/**
24+
* Implementation of {@link CassandraRepositoryFragmentsContributor} that contributes empty fragments by default.
25+
*
26+
* @author Chris Bono
27+
* @since 5.0
28+
*/
29+
enum EmptyFragmentsContributor implements CassandraRepositoryFragmentsContributor {
30+
31+
INSTANCE;
32+
33+
@Override
34+
public RepositoryComposition.RepositoryFragments contribute(RepositoryMetadata metadata,
35+
CassandraEntityInformation<?, ?> entityInformation, CassandraOperations operations) {
36+
return RepositoryComposition.RepositoryFragments.empty();
37+
}
38+
39+
@Override
40+
public RepositoryComposition.RepositoryFragments describe(RepositoryMetadata metadata) {
41+
return RepositoryComposition.RepositoryFragments.empty();
42+
}
43+
}

0 commit comments

Comments
 (0)