Skip to content

Commit 3bd0b2a

Browse files
Add Support SupplierReactiveClientRegistrationRepository
Closes spring-projectsgh-16750 Signed-off-by: Max Batischev <[email protected]>
1 parent 4dd4813 commit 3bd0b2a

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2002-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+
17+
package org.springframework.security.oauth2.client.registration;
18+
19+
import java.util.Iterator;
20+
import java.util.function.Supplier;
21+
22+
import reactor.core.publisher.Mono;
23+
24+
import org.springframework.util.Assert;
25+
import org.springframework.util.function.SingletonSupplier;
26+
27+
/**
28+
* A {@link ReactiveClientRegistrationRepository} that lazily calls to retrieve
29+
* {@link ClientRegistration}(s) when requested.
30+
*
31+
* @author Max Batischev
32+
* @since 6.5
33+
* @see ReactiveClientRegistrationRepository
34+
* @see ClientRegistration
35+
*/
36+
public final class SupplierReactiveClientRegistrationRepository
37+
implements ReactiveClientRegistrationRepository, Iterable<ClientRegistration> {
38+
39+
private final Supplier<? extends ReactiveClientRegistrationRepository> repositorySupplier;
40+
41+
/**
42+
* Constructs an {@code SupplierReactiveClientRegistrationRepository} using the
43+
* provided parameters.
44+
* @param repositorySupplier the client registration repository supplier
45+
*/
46+
public <T extends ReactiveClientRegistrationRepository & Iterable<ClientRegistration>> SupplierReactiveClientRegistrationRepository(
47+
Supplier<? extends ReactiveClientRegistrationRepository> repositorySupplier) {
48+
Assert.notNull(repositorySupplier, "repositorySupplier cannot be null");
49+
this.repositorySupplier = SingletonSupplier.of(repositorySupplier);
50+
}
51+
52+
@Override
53+
public Mono<ClientRegistration> findByRegistrationId(String registrationId) {
54+
Assert.hasText(registrationId, "registrationId cannot be empty");
55+
return this.repositorySupplier.get().findByRegistrationId(registrationId);
56+
}
57+
58+
/**
59+
* Returns an {@code Iterator} of {@link ClientRegistration}.
60+
* @return an {@code Iterator<ClientRegistration>}
61+
*/
62+
@Override
63+
public Iterator<ClientRegistration> iterator() {
64+
return ((Iterable<ClientRegistration>) this.repositorySupplier.get()).iterator();
65+
}
66+
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2002-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+
17+
package org.springframework.security.oauth2.client.registration;
18+
19+
import java.util.function.Supplier;
20+
21+
import org.junit.jupiter.api.Test;
22+
import org.junit.jupiter.api.extension.ExtendWith;
23+
import org.mockito.Mock;
24+
import org.mockito.junit.jupiter.MockitoExtension;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
28+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
29+
import static org.mockito.BDDMockito.given;
30+
import static org.mockito.Mockito.times;
31+
import static org.mockito.Mockito.verify;
32+
33+
/**
34+
* Tests for {@link SupplierReactiveClientRegistrationRepository}.
35+
*
36+
* @author Max Batischev
37+
*/
38+
@ExtendWith(MockitoExtension.class)
39+
public class SupplierReactiveClientRegistrationRepositoryTests {
40+
41+
private final ClientRegistration registration = TestClientRegistrations.clientRegistration().build();
42+
43+
private final SupplierReactiveClientRegistrationRepository registrationRepository = new SupplierReactiveClientRegistrationRepository(
44+
() -> new InMemoryReactiveClientRegistrationRepository(this.registration));
45+
46+
@Mock
47+
private Supplier<InMemoryReactiveClientRegistrationRepository> clientRegistrationRepositorySupplier;
48+
49+
@Test
50+
void constructWhenNullThenIllegalArgumentException() {
51+
assertThatIllegalArgumentException().isThrownBy(() -> new SupplierReactiveClientRegistrationRepository(null));
52+
}
53+
54+
@Test
55+
public void findRegistrationWhenRegistrationIsPresentThenReturns() {
56+
String id = this.registration.getRegistrationId();
57+
assertThat(this.registrationRepository.findByRegistrationId(id).block()).isEqualTo(this.registration);
58+
}
59+
60+
@Test
61+
public void findRegistrationWhenRegistrationIsNotPresentThenNull() {
62+
String id = this.registration.getRegistrationId() + "MISSING";
63+
assertThat(this.registrationRepository.findByRegistrationId(id).block()).isNull();
64+
}
65+
66+
@Test
67+
public void findRegistrationWhenNullIdIsPresentThenThrowsException() {
68+
assertThatIllegalArgumentException()
69+
.isThrownBy(() -> this.registrationRepository.findByRegistrationId(null).block());
70+
}
71+
72+
@Test
73+
public void findRegistrationWhenIdIsPresentThenSingletonSupplierCached() {
74+
given(this.clientRegistrationRepositorySupplier.get())
75+
.willReturn(new InMemoryReactiveClientRegistrationRepository(this.registration));
76+
SupplierReactiveClientRegistrationRepository test = new SupplierReactiveClientRegistrationRepository(
77+
this.clientRegistrationRepositorySupplier);
78+
79+
String id = this.registration.getRegistrationId();
80+
assertThat(test.findByRegistrationId(id).block()).isEqualTo(this.registration);
81+
82+
id = this.registration.getRegistrationId();
83+
assertThat(test.findByRegistrationId(id).block()).isEqualTo(this.registration);
84+
verify(this.clientRegistrationRepositorySupplier, times(1)).get();
85+
}
86+
87+
@Test
88+
public void iteratorWhenRemoveThenThrowsUnsupportedOperationException() {
89+
assertThatExceptionOfType(UnsupportedOperationException.class)
90+
.isThrownBy(this.registrationRepository.iterator()::remove);
91+
}
92+
93+
@Test
94+
public void iteratorWhenGetThenContainsAll() {
95+
assertThat(this.registrationRepository).containsOnly(this.registration);
96+
}
97+
98+
}

0 commit comments

Comments
 (0)