Fix indentation to use tabs in Kotlin source files

Closes gh-33840
This commit is contained in:
Johnny Lim 2024-11-04 21:40:14 +09:00 committed by Sébastien Deleuze
parent 6bd4687706
commit 0beb56a58c
11 changed files with 483 additions and 483 deletions

View File

@ -56,33 +56,33 @@ import kotlin.annotation.AnnotationTarget.TYPE
@SpringJUnitConfig(InterceptorConfig::class) @SpringJUnitConfig(InterceptorConfig::class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class AspectJAutoProxyInterceptorKotlinIntegrationTests( class AspectJAutoProxyInterceptorKotlinIntegrationTests(
@Autowired val echo: Echo, @Autowired val echo: Echo,
@Autowired val firstAdvisor: TestPointcutAdvisor, @Autowired val firstAdvisor: TestPointcutAdvisor,
@Autowired val secondAdvisor: TestPointcutAdvisor, @Autowired val secondAdvisor: TestPointcutAdvisor,
@Autowired val countingAspect: CountingAspect, @Autowired val countingAspect: CountingAspect,
@Autowired val reactiveTransactionManager: ReactiveCallCountingTransactionManager) { @Autowired val reactiveTransactionManager: ReactiveCallCountingTransactionManager) {
@Test @Test
fun `Multiple interceptors with regular function`() { fun `Multiple interceptors with regular function`() {
assertThat(firstAdvisor.interceptor.invocations).isEmpty() assertThat(firstAdvisor.interceptor.invocations).isEmpty()
assertThat(secondAdvisor.interceptor.invocations).isEmpty() assertThat(secondAdvisor.interceptor.invocations).isEmpty()
val value = "Hello!" val value = "Hello!"
assertThat(echo.echo(value)).isEqualTo(value) assertThat(echo.echo(value)).isEqualTo(value)
assertThat(firstAdvisor.interceptor.invocations).singleElement().matches { String::class.java.isAssignableFrom(it) } assertThat(firstAdvisor.interceptor.invocations).singleElement().matches { String::class.java.isAssignableFrom(it) }
assertThat(secondAdvisor.interceptor.invocations).singleElement().matches { String::class.java.isAssignableFrom(it) } assertThat(secondAdvisor.interceptor.invocations).singleElement().matches { String::class.java.isAssignableFrom(it) }
} }
@Test @Test
fun `Multiple interceptors with suspending function`() { fun `Multiple interceptors with suspending function`() {
assertThat(firstAdvisor.interceptor.invocations).isEmpty() assertThat(firstAdvisor.interceptor.invocations).isEmpty()
assertThat(secondAdvisor.interceptor.invocations).isEmpty() assertThat(secondAdvisor.interceptor.invocations).isEmpty()
val value = "Hello!" val value = "Hello!"
runBlocking { runBlocking {
assertThat(echo.suspendingEcho(value)).isEqualTo(value) assertThat(echo.suspendingEcho(value)).isEqualTo(value)
} }
assertThat(firstAdvisor.interceptor.invocations).singleElement().matches { Mono::class.java.isAssignableFrom(it) } assertThat(firstAdvisor.interceptor.invocations).singleElement().matches { Mono::class.java.isAssignableFrom(it) }
assertThat(secondAdvisor.interceptor.invocations).singleElement().matches { Mono::class.java.isAssignableFrom(it) } assertThat(secondAdvisor.interceptor.invocations).singleElement().matches { Mono::class.java.isAssignableFrom(it) }
} }
@Test // gh-33095 @Test // gh-33095
fun `Aspect and reactive transactional with suspending function`() { fun `Aspect and reactive transactional with suspending function`() {
@ -113,17 +113,17 @@ class AspectJAutoProxyInterceptorKotlinIntegrationTests(
assertThat(countingAspect.counter).`as`("aspect applied once per key").isEqualTo(2) assertThat(countingAspect.counter).`as`("aspect applied once per key").isEqualTo(2)
} }
@Configuration @Configuration
@EnableAspectJAutoProxy @EnableAspectJAutoProxy
@EnableTransactionManagement @EnableTransactionManagement
@EnableCaching @EnableCaching
open class InterceptorConfig { open class InterceptorConfig {
@Bean @Bean
open fun firstAdvisor() = TestPointcutAdvisor().apply { order = 0 } open fun firstAdvisor() = TestPointcutAdvisor().apply { order = 0 }
@Bean @Bean
open fun secondAdvisor() = TestPointcutAdvisor().apply { order = 1 } open fun secondAdvisor() = TestPointcutAdvisor().apply { order = 1 }
@Bean @Bean
open fun countingAspect() = CountingAspect() open fun countingAspect() = CountingAspect()
@ -138,34 +138,34 @@ class AspectJAutoProxyInterceptorKotlinIntegrationTests(
return ConcurrentMapCacheManager() return ConcurrentMapCacheManager()
} }
@Bean @Bean
open fun echo(): Echo { open fun echo(): Echo {
return Echo() return Echo()
} }
} }
class TestMethodInterceptor: MethodInterceptor { class TestMethodInterceptor: MethodInterceptor {
var invocations: MutableList<Class<*>> = mutableListOf() var invocations: MutableList<Class<*>> = mutableListOf()
@Suppress("RedundantNullableReturnType") @Suppress("RedundantNullableReturnType")
override fun invoke(invocation: MethodInvocation): Any? { override fun invoke(invocation: MethodInvocation): Any? {
val result = invocation.proceed() val result = invocation.proceed()
invocations.add(result!!.javaClass) invocations.add(result!!.javaClass)
return result return result
} }
} }
class TestPointcutAdvisor : StaticMethodMatcherPointcutAdvisor(TestMethodInterceptor()) { class TestPointcutAdvisor : StaticMethodMatcherPointcutAdvisor(TestMethodInterceptor()) {
val interceptor: TestMethodInterceptor val interceptor: TestMethodInterceptor
get() = advice as TestMethodInterceptor get() = advice as TestMethodInterceptor
override fun matches(method: Method, targetClass: Class<*>): Boolean { override fun matches(method: Method, targetClass: Class<*>): Boolean {
return targetClass == Echo::class.java && method.name.lowercase().endsWith("echo") return targetClass == Echo::class.java && method.name.lowercase().endsWith("echo")
} }
} }
@Target(CLASS, FUNCTION, ANNOTATION_CLASS, TYPE) @Target(CLASS, FUNCTION, ANNOTATION_CLASS, TYPE)
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
@ -185,16 +185,16 @@ class AspectJAutoProxyInterceptorKotlinIntegrationTests(
} }
} }
open class Echo { open class Echo {
open fun echo(value: String): String { open fun echo(value: String): String {
return value return value
} }
open suspend fun suspendingEcho(value: String): String { open suspend fun suspendingEcho(value: String): String {
delay(1) delay(1)
return value return value
} }
@Transactional @Transactional
@Counting @Counting
@ -212,6 +212,6 @@ class AspectJAutoProxyInterceptorKotlinIntegrationTests(
return "$value ${cacheCounter++}" return "$value ${cacheCounter++}"
} }
} }
} }

View File

@ -31,17 +31,17 @@ import kotlin.coroutines.Continuation
*/ */
class AopUtilsKotlinTests { class AopUtilsKotlinTests {
@Test @Test
fun `Invoking suspending function should return Mono`() { fun `Invoking suspending function should return Mono`() {
val value = "foo" val value = "foo"
val method = ReflectionUtils.findMethod(WithoutInterface::class.java, "handle", val method = ReflectionUtils.findMethod(WithoutInterface::class.java, "handle",
String::class. java, Continuation::class.java)!! String::class. java, Continuation::class.java)!!
val continuation = Continuation<Any>(CoroutineName("test")) { } val continuation = Continuation<Any>(CoroutineName("test")) { }
val result = AopUtils.invokeJoinpointUsingReflection(WithoutInterface(), method, arrayOf(value, continuation)) val result = AopUtils.invokeJoinpointUsingReflection(WithoutInterface(), method, arrayOf(value, continuation))
assertThat(result).isInstanceOfSatisfying(Mono::class.java) { assertThat(result).isInstanceOfSatisfying(Mono::class.java) {
assertThat(it.block()).isEqualTo(value) assertThat(it.block()).isEqualTo(value)
} }
} }
@Test @Test
fun `Invoking suspending function on bridged method should return Mono`() { fun `Invoking suspending function on bridged method should return Mono`() {
@ -54,11 +54,11 @@ class AopUtilsKotlinTests {
} }
} }
@Suppress("unused") @Suppress("unused")
suspend fun suspendingFunction(value: String): String { suspend fun suspendingFunction(value: String): String {
delay(1) delay(1)
return value return value
} }
class WithoutInterface { class WithoutInterface {
suspend fun handle(value: String): String { suspend fun handle(value: String): String {

View File

@ -45,99 +45,99 @@ import javax.lang.model.element.Modifier
*/ */
class InstanceSupplierCodeGeneratorKotlinTests { class InstanceSupplierCodeGeneratorKotlinTests {
private val generationContext = TestGenerationContext() private val generationContext = TestGenerationContext()
@Test @Test
fun generateWhenHasDefaultConstructor() { fun generateWhenHasDefaultConstructor() {
val beanDefinition: BeanDefinition = RootBeanDefinition(KotlinTestBean::class.java) val beanDefinition: BeanDefinition = RootBeanDefinition(KotlinTestBean::class.java)
val beanFactory = DefaultListableBeanFactory() val beanFactory = DefaultListableBeanFactory()
compile(beanFactory, beanDefinition) { instanceSupplier, compiled -> compile(beanFactory, beanDefinition) { instanceSupplier, compiled ->
val bean = getBean<KotlinTestBean>(beanFactory, beanDefinition, instanceSupplier) val bean = getBean<KotlinTestBean>(beanFactory, beanDefinition, instanceSupplier)
Assertions.assertThat(bean).isInstanceOf(KotlinTestBean::class.java) Assertions.assertThat(bean).isInstanceOf(KotlinTestBean::class.java)
Assertions.assertThat(compiled.sourceFile).contains("InstanceSupplier.using(KotlinTestBean::new)") Assertions.assertThat(compiled.sourceFile).contains("InstanceSupplier.using(KotlinTestBean::new)")
} }
Assertions.assertThat(getReflectionHints().getTypeHint(KotlinTestBean::class.java)) Assertions.assertThat(getReflectionHints().getTypeHint(KotlinTestBean::class.java))
.satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT)) .satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT))
} }
@Test @Test
fun generateWhenConstructorHasOptionalParameter() { fun generateWhenConstructorHasOptionalParameter() {
val beanDefinition: BeanDefinition = RootBeanDefinition(KotlinTestBeanWithOptionalParameter::class.java) val beanDefinition: BeanDefinition = RootBeanDefinition(KotlinTestBeanWithOptionalParameter::class.java)
val beanFactory = DefaultListableBeanFactory() val beanFactory = DefaultListableBeanFactory()
compile(beanFactory, beanDefinition) { instanceSupplier, compiled -> compile(beanFactory, beanDefinition) { instanceSupplier, compiled ->
val bean: KotlinTestBeanWithOptionalParameter = getBean(beanFactory, beanDefinition, instanceSupplier) val bean: KotlinTestBeanWithOptionalParameter = getBean(beanFactory, beanDefinition, instanceSupplier)
Assertions.assertThat(bean).isInstanceOf(KotlinTestBeanWithOptionalParameter::class.java) Assertions.assertThat(bean).isInstanceOf(KotlinTestBeanWithOptionalParameter::class.java)
Assertions.assertThat(compiled.sourceFile) Assertions.assertThat(compiled.sourceFile)
.contains("return BeanInstanceSupplier.<KotlinTestBeanWithOptionalParameter>forConstructor();") .contains("return BeanInstanceSupplier.<KotlinTestBeanWithOptionalParameter>forConstructor();")
} }
Assertions.assertThat<TypeHint>(getReflectionHints().getTypeHint(KotlinTestBeanWithOptionalParameter::class.java)) Assertions.assertThat<TypeHint>(getReflectionHints().getTypeHint(KotlinTestBeanWithOptionalParameter::class.java))
.satisfies(hasMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)) .satisfies(hasMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS))
} }
private fun getReflectionHints(): ReflectionHints { private fun getReflectionHints(): ReflectionHints {
return generationContext.runtimeHints.reflection() return generationContext.runtimeHints.reflection()
} }
private fun hasConstructorWithMode(mode: ExecutableMode): ThrowingConsumer<TypeHint> { private fun hasConstructorWithMode(mode: ExecutableMode): ThrowingConsumer<TypeHint> {
return ThrowingConsumer { return ThrowingConsumer {
Assertions.assertThat(it.constructors()).anySatisfy(hasMode(mode)) Assertions.assertThat(it.constructors()).anySatisfy(hasMode(mode))
} }
} }
private fun hasMemberCategory(category: MemberCategory): ThrowingConsumer<TypeHint> { private fun hasMemberCategory(category: MemberCategory): ThrowingConsumer<TypeHint> {
return ThrowingConsumer { return ThrowingConsumer {
Assertions.assertThat(it.memberCategories).contains(category) Assertions.assertThat(it.memberCategories).contains(category)
} }
} }
private fun hasMode(mode: ExecutableMode): ThrowingConsumer<ExecutableHint> { private fun hasMode(mode: ExecutableMode): ThrowingConsumer<ExecutableHint> {
return ThrowingConsumer { return ThrowingConsumer {
Assertions.assertThat(it.mode).isEqualTo(mode) Assertions.assertThat(it.mode).isEqualTo(mode)
} }
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun <T> getBean(beanFactory: DefaultListableBeanFactory, beanDefinition: BeanDefinition, private fun <T> getBean(beanFactory: DefaultListableBeanFactory, beanDefinition: BeanDefinition,
instanceSupplier: InstanceSupplier<*>): T { instanceSupplier: InstanceSupplier<*>): T {
(beanDefinition as RootBeanDefinition).instanceSupplier = instanceSupplier (beanDefinition as RootBeanDefinition).instanceSupplier = instanceSupplier
beanFactory.registerBeanDefinition("testBean", beanDefinition) beanFactory.registerBeanDefinition("testBean", beanDefinition)
return beanFactory.getBean("testBean") as T return beanFactory.getBean("testBean") as T
} }
private fun compile(beanFactory: DefaultListableBeanFactory, beanDefinition: BeanDefinition, private fun compile(beanFactory: DefaultListableBeanFactory, beanDefinition: BeanDefinition,
result: BiConsumer<InstanceSupplier<*>, Compiled>) { result: BiConsumer<InstanceSupplier<*>, Compiled>) {
val freshBeanFactory = DefaultListableBeanFactory(beanFactory) val freshBeanFactory = DefaultListableBeanFactory(beanFactory)
freshBeanFactory.registerBeanDefinition("testBean", beanDefinition) freshBeanFactory.registerBeanDefinition("testBean", beanDefinition)
val registeredBean = RegisteredBean.of(freshBeanFactory, "testBean") val registeredBean = RegisteredBean.of(freshBeanFactory, "testBean")
val typeBuilder = DeferredTypeBuilder() val typeBuilder = DeferredTypeBuilder()
val generateClass = generationContext.generatedClasses.addForFeature("TestCode", typeBuilder) val generateClass = generationContext.generatedClasses.addForFeature("TestCode", typeBuilder)
val generator = InstanceSupplierCodeGenerator( val generator = InstanceSupplierCodeGenerator(
generationContext, generateClass.name, generationContext, generateClass.name,
generateClass.methods, false generateClass.methods, false
) )
val instantiationDescriptor = registeredBean.resolveInstantiationDescriptor() val instantiationDescriptor = registeredBean.resolveInstantiationDescriptor()
Assertions.assertThat(instantiationDescriptor).isNotNull() Assertions.assertThat(instantiationDescriptor).isNotNull()
val generatedCode = generator.generateCode(registeredBean, instantiationDescriptor) val generatedCode = generator.generateCode(registeredBean, instantiationDescriptor)
typeBuilder.set { type: TypeSpec.Builder -> typeBuilder.set { type: TypeSpec.Builder ->
type.addModifiers(Modifier.PUBLIC) type.addModifiers(Modifier.PUBLIC)
type.addSuperinterface( type.addSuperinterface(
ParameterizedTypeName.get( ParameterizedTypeName.get(
Supplier::class.java, Supplier::class.java,
InstanceSupplier::class.java InstanceSupplier::class.java
) )
) )
type.addMethod( type.addMethod(
MethodSpec.methodBuilder("get") MethodSpec.methodBuilder("get")
.addModifiers(Modifier.PUBLIC) .addModifiers(Modifier.PUBLIC)
.returns(InstanceSupplier::class.java) .returns(InstanceSupplier::class.java)
.addStatement("return \$L", generatedCode).build() .addStatement("return \$L", generatedCode).build()
) )
} }
generationContext.writeGeneratedContent() generationContext.writeGeneratedContent()
TestCompiler.forSystem().with(generationContext).compile { TestCompiler.forSystem().with(generationContext).compile {
result.accept(it.getInstance(Supplier::class.java).get() as InstanceSupplier<*>, it) result.accept(it.getInstance(Supplier::class.java).get() as InstanceSupplier<*>, it)
} }
} }
} }

View File

@ -36,45 +36,45 @@ import org.springframework.validation.beanvalidation.BeanValidationBeanRegistrat
*/ */
class BeanValidationBeanRegistrationAotProcessorKotlinTests { class BeanValidationBeanRegistrationAotProcessorKotlinTests {
private val processor = BeanValidationBeanRegistrationAotProcessor() private val processor = BeanValidationBeanRegistrationAotProcessor()
private val generationContext: GenerationContext = TestGenerationContext() private val generationContext: GenerationContext = TestGenerationContext()
@Test @Test
fun shouldProcessMethodParameterLevelConstraint() { fun shouldProcessMethodParameterLevelConstraint() {
process(MethodParameterLevelConstraint::class.java) process(MethodParameterLevelConstraint::class.java)
Assertions.assertThat( Assertions.assertThat(
RuntimeHintsPredicates.reflection().onType(ExistsValidator::class.java) RuntimeHintsPredicates.reflection().onType(ExistsValidator::class.java)
.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS) .withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)
).accepts(generationContext.runtimeHints) ).accepts(generationContext.runtimeHints)
} }
@Test @Test
fun shouldSkipMethodParameterLevelConstraintWihExtension() { fun shouldSkipMethodParameterLevelConstraintWihExtension() {
process(MethodParameterLevelConstraintWithExtension::class.java) process(MethodParameterLevelConstraintWithExtension::class.java)
Assertions.assertThat(generationContext.runtimeHints.reflection().typeHints()).isEmpty() Assertions.assertThat(generationContext.runtimeHints.reflection().typeHints()).isEmpty()
} }
private fun process(beanClass: Class<*>) { private fun process(beanClass: Class<*>) {
val contribution = createContribution(beanClass) val contribution = createContribution(beanClass)
contribution?.applyTo(generationContext, Mockito.mock()) contribution?.applyTo(generationContext, Mockito.mock())
} }
private fun createContribution(beanClass: Class<*>): BeanRegistrationAotContribution? { private fun createContribution(beanClass: Class<*>): BeanRegistrationAotContribution? {
val beanFactory = DefaultListableBeanFactory() val beanFactory = DefaultListableBeanFactory()
beanFactory.registerBeanDefinition(beanClass.name, RootBeanDefinition(beanClass)) beanFactory.registerBeanDefinition(beanClass.name, RootBeanDefinition(beanClass))
return processor.processAheadOfTime(RegisteredBean.of(beanFactory, beanClass.name)) return processor.processAheadOfTime(RegisteredBean.of(beanFactory, beanClass.name))
} }
internal class MethodParameterLevelConstraintWithExtension { internal class MethodParameterLevelConstraintWithExtension {
@Suppress("unused") @Suppress("unused")
fun hello(name: @Exists String): String { fun hello(name: @Exists String): String {
return name.toHello() return name.toHello()
} }
private fun String.toHello() = private fun String.toHello() =
"Hello $this" "Hello $this"
} }
} }

View File

@ -22,4 +22,4 @@ package org.springframework.core
* @author Sebastien Deleuze * @author Sebastien Deleuze
*/ */
class KotlinReflectionParameterNameDiscovererTests : class KotlinReflectionParameterNameDiscovererTests :
AbstractReflectionParameterNameDiscovererKotlinTests(KotlinReflectionParameterNameDiscoverer()) AbstractReflectionParameterNameDiscovererKotlinTests(KotlinReflectionParameterNameDiscoverer())

View File

@ -51,142 +51,142 @@ class SimpAnnotationMethodMessageHandlerKotlinTests {
lateinit var testController: TestController lateinit var testController: TestController
val channel = mockk<SubscribableChannel>(relaxed = true) val channel = mockk<SubscribableChannel>(relaxed = true)
val converter = mockk<MessageConverter>(relaxed = true) val converter = mockk<MessageConverter>(relaxed = true)
@BeforeEach @BeforeEach
fun setup() { fun setup() {
val brokerTemplate = SimpMessagingTemplate(channel) val brokerTemplate = SimpMessagingTemplate(channel)
brokerTemplate.messageConverter = converter brokerTemplate.messageConverter = converter
messageHandler = TestSimpAnnotationMethodMessageHandler(brokerTemplate, channel, channel) messageHandler = TestSimpAnnotationMethodMessageHandler(brokerTemplate, channel, channel)
messageHandler.applicationContext = StaticApplicationContext() messageHandler.applicationContext = StaticApplicationContext()
messageHandler.afterPropertiesSet() messageHandler.afterPropertiesSet()
testController = TestController() testController = TestController()
} }
@Test @Test
fun nullableHeaderWithHeader() { fun nullableHeaderWithHeader() {
val message = createMessage("/nullableHeader", Collections.singletonMap("foo", "bar")) val message = createMessage("/nullableHeader", Collections.singletonMap("foo", "bar"))
messageHandler.registerHandler(testController) messageHandler.registerHandler(testController)
messageHandler.handleMessage(message) messageHandler.handleMessage(message)
assertThat(testController.exception).isNull() assertThat(testController.exception).isNull()
assertThat(testController.header).isEqualTo("bar") assertThat(testController.header).isEqualTo("bar")
} }
@Test @Test
fun nullableHeaderWithoutHeader() { fun nullableHeaderWithoutHeader() {
val message = createMessage("/nullableHeader", Collections.emptyMap()) val message = createMessage("/nullableHeader", Collections.emptyMap())
messageHandler.registerHandler(testController) messageHandler.registerHandler(testController)
messageHandler.handleMessage(message) messageHandler.handleMessage(message)
assertThat(testController.exception).isNull() assertThat(testController.exception).isNull()
assertThat(testController.header).isNull() assertThat(testController.header).isNull()
} }
@Test @Test
fun nonNullableHeaderWithHeader() { fun nonNullableHeaderWithHeader() {
val message = createMessage("/nonNullableHeader", Collections.singletonMap("foo", "bar")) val message = createMessage("/nonNullableHeader", Collections.singletonMap("foo", "bar"))
messageHandler.registerHandler(testController) messageHandler.registerHandler(testController)
messageHandler.handleMessage(message) messageHandler.handleMessage(message)
assertThat(testController.header).isEqualTo("bar") assertThat(testController.header).isEqualTo("bar")
} }
@Test @Test
fun nonNullableHeaderWithoutHeader() { fun nonNullableHeaderWithoutHeader() {
val message = createMessage("/nonNullableHeader", Collections.emptyMap()) val message = createMessage("/nonNullableHeader", Collections.emptyMap())
messageHandler.registerHandler(testController) messageHandler.registerHandler(testController)
messageHandler.handleMessage(message) messageHandler.handleMessage(message)
assertThat(testController.exception).isNotNull() assertThat(testController.exception).isNotNull()
assertThat(testController.exception).isInstanceOf(MessageHandlingException::class.java) assertThat(testController.exception).isInstanceOf(MessageHandlingException::class.java)
} }
@Test @Test
fun nullableHeaderNotRequiredWithHeader() { fun nullableHeaderNotRequiredWithHeader() {
val message = createMessage("/nullableHeaderNotRequired", Collections.singletonMap("foo", "bar")) val message = createMessage("/nullableHeaderNotRequired", Collections.singletonMap("foo", "bar"))
messageHandler.registerHandler(testController) messageHandler.registerHandler(testController)
messageHandler.handleMessage(message) messageHandler.handleMessage(message)
assertThat(testController.exception).isNull() assertThat(testController.exception).isNull()
assertThat(testController.header).isEqualTo("bar") assertThat(testController.header).isEqualTo("bar")
} }
@Test @Test
fun nullableHeaderNotRequiredWithoutHeader() { fun nullableHeaderNotRequiredWithoutHeader() {
val message = createMessage("/nullableHeaderNotRequired", Collections.emptyMap()) val message = createMessage("/nullableHeaderNotRequired", Collections.emptyMap())
messageHandler.registerHandler(testController) messageHandler.registerHandler(testController)
messageHandler.handleMessage(message) messageHandler.handleMessage(message)
assertThat(testController.exception).isNull() assertThat(testController.exception).isNull()
assertThat(testController.header).isNull() assertThat(testController.header).isNull()
} }
@Test @Test
fun nonNullableHeaderNotRequiredWithHeader() { fun nonNullableHeaderNotRequiredWithHeader() {
val message = createMessage("/nonNullableHeaderNotRequired", Collections.singletonMap("foo", "bar")) val message = createMessage("/nonNullableHeaderNotRequired", Collections.singletonMap("foo", "bar"))
messageHandler.registerHandler(testController) messageHandler.registerHandler(testController)
messageHandler.handleMessage(message) messageHandler.handleMessage(message)
assertThat(testController.header).isEqualTo("bar") assertThat(testController.header).isEqualTo("bar")
} }
@Test @Test
fun nonNullableHeaderNotRequiredWithoutHeader() { fun nonNullableHeaderNotRequiredWithoutHeader() {
val message = createMessage("/nonNullableHeaderNotRequired", Collections.emptyMap()) val message = createMessage("/nonNullableHeaderNotRequired", Collections.emptyMap())
messageHandler.registerHandler(testController) messageHandler.registerHandler(testController)
messageHandler.handleMessage(message) messageHandler.handleMessage(message)
assertThat(testController.exception).isNotNull() assertThat(testController.exception).isNotNull()
assertThat(testController.exception).isInstanceOf(NullPointerException::class.java) assertThat(testController.exception).isInstanceOf(NullPointerException::class.java)
} }
private fun createMessage(destination: String, headers: Map<String, String?>): Message<ByteArray> { private fun createMessage(destination: String, headers: Map<String, String?>): Message<ByteArray> {
val accessor = SimpMessageHeaderAccessor.create() val accessor = SimpMessageHeaderAccessor.create()
accessor.sessionId = "session1" accessor.sessionId = "session1"
accessor.sessionAttributes = HashMap() accessor.sessionAttributes = HashMap()
accessor.destination = destination accessor.destination = destination
for (entry in headers.entries) accessor.setHeader(entry.key, entry.value) for (entry in headers.entries) accessor.setHeader(entry.key, entry.value)
return MessageBuilder.withPayload(ByteArray(0)).setHeaders(accessor).build() return MessageBuilder.withPayload(ByteArray(0)).setHeaders(accessor).build()
} }
class TestSimpAnnotationMethodMessageHandler(brokerTemplate: SimpMessageSendingOperations, class TestSimpAnnotationMethodMessageHandler(brokerTemplate: SimpMessageSendingOperations,
clientInboundChannel: SubscribableChannel, clientInboundChannel: SubscribableChannel,
clientOutboundChannel: MessageChannel) : clientOutboundChannel: MessageChannel) :
SimpAnnotationMethodMessageHandler(clientInboundChannel, clientOutboundChannel, brokerTemplate) { SimpAnnotationMethodMessageHandler(clientInboundChannel, clientOutboundChannel, brokerTemplate) {
fun registerHandler(handler: Any) { fun registerHandler(handler: Any) {
super.detectHandlerMethods(handler) super.detectHandlerMethods(handler)
} }
} }
@Suppress("unused") @Suppress("unused")
@Controller @Controller
@MessageMapping @MessageMapping
class TestController { class TestController {
var header: String? = null var header: String? = null
var exception: Throwable? = null var exception: Throwable? = null
@MessageMapping("/nullableHeader") @MessageMapping("/nullableHeader")
fun nullableHeader(@Header("foo") foo: String?) { fun nullableHeader(@Header("foo") foo: String?) {
header = foo header = foo
} }
@MessageMapping("/nonNullableHeader") @MessageMapping("/nonNullableHeader")
fun nonNullableHeader(@Header("foo") foo: String) { fun nonNullableHeader(@Header("foo") foo: String) {
header = foo header = foo
} }
@MessageMapping("/nullableHeaderNotRequired") @MessageMapping("/nullableHeaderNotRequired")
fun nullableHeaderNotRequired(@Header("foo", required = false) foo: String?) { fun nullableHeaderNotRequired(@Header("foo", required = false) foo: String?) {
header = foo header = foo
} }
@MessageMapping("/nonNullableHeaderNotRequired") @MessageMapping("/nonNullableHeaderNotRequired")
fun nonNullableHeaderNotRequired(@Header("foo", required = false) foo: String) { fun nonNullableHeaderNotRequired(@Header("foo", required = false) foo: String) {
header = foo header = foo
} }
@MessageExceptionHandler @MessageExceptionHandler
fun handleIllegalArgumentException(exception: Throwable) { fun handleIllegalArgumentException(exception: Throwable) {
this.exception = exception this.exception = exception
} }
} }
} }

View File

@ -66,4 +66,4 @@ suspend fun ServerWebExchange.awaitSession(): WebSession =
* @since 6.1 * @since 6.1
*/ */
fun ServerWebExchange.Builder.principal(supplier: suspend () -> Principal): ServerWebExchange.Builder fun ServerWebExchange.Builder.principal(supplier: suspend () -> Principal): ServerWebExchange.Builder
= principal(mono(Dispatchers.Unconfined) { supplier.invoke() }) = principal(mono(Dispatchers.Unconfined) { supplier.invoke() })

View File

@ -49,139 +49,139 @@ import java.util.*
*/ */
class KotlinRestTemplateHttpServiceProxyTests { class KotlinRestTemplateHttpServiceProxyTests {
private lateinit var server: MockWebServer private lateinit var server: MockWebServer
private lateinit var testService: TestService private lateinit var testService: TestService
private lateinit var anotherServer: MockWebServer private lateinit var anotherServer: MockWebServer
@BeforeEach @BeforeEach
fun setUp() { fun setUp() {
server = MockWebServer() server = MockWebServer()
prepareResponse() prepareResponse()
anotherServer = anotherServer() anotherServer = anotherServer()
testService = initTestService() testService = initTestService()
} }
private fun initTestService(): TestService { private fun initTestService(): TestService {
val restTemplate = RestTemplate() val restTemplate = RestTemplate()
restTemplate.uriTemplateHandler = DefaultUriBuilderFactory(server.url("/").toString()) restTemplate.uriTemplateHandler = DefaultUriBuilderFactory(server.url("/").toString())
return HttpServiceProxyFactory.builder() return HttpServiceProxyFactory.builder()
.exchangeAdapter(RestTemplateAdapter.create(restTemplate)) .exchangeAdapter(RestTemplateAdapter.create(restTemplate))
.build() .build()
.createClient(TestService::class.java) .createClient(TestService::class.java)
} }
@AfterEach @AfterEach
fun shutDown() { fun shutDown() {
server.shutdown() server.shutdown()
anotherServer.shutdown() anotherServer.shutdown()
} }
@Test @Test
@Throws(InterruptedException::class) @Throws(InterruptedException::class)
fun getRequest() { fun getRequest() {
val response = testService.request val response = testService.request
val request = server.takeRequest() val request = server.takeRequest()
assertThat(response).isEqualTo("Hello Spring!") assertThat(response).isEqualTo("Hello Spring!")
assertThat(request.method).isEqualTo("GET") assertThat(request.method).isEqualTo("GET")
assertThat(request.path).isEqualTo("/test") assertThat(request.path).isEqualTo("/test")
} }
@Test @Test
@Throws(InterruptedException::class) @Throws(InterruptedException::class)
fun getRequestWithPathVariable() { fun getRequestWithPathVariable() {
val response = testService.getRequestWithPathVariable("456") val response = testService.getRequestWithPathVariable("456")
val request = server.takeRequest() val request = server.takeRequest()
assertThat(response.statusCode).isEqualTo(HttpStatus.OK) assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
assertThat(response.body).isEqualTo("Hello Spring!") assertThat(response.body).isEqualTo("Hello Spring!")
assertThat(request.method).isEqualTo("GET") assertThat(request.method).isEqualTo("GET")
assertThat(request.path).isEqualTo("/test/456") assertThat(request.path).isEqualTo("/test/456")
} }
@Test @Test
@Throws(InterruptedException::class) @Throws(InterruptedException::class)
fun getRequestWithDynamicUri() { fun getRequestWithDynamicUri() {
val dynamicUri = server.url("/greeting/123").uri() val dynamicUri = server.url("/greeting/123").uri()
val response = testService.getRequestWithDynamicUri(dynamicUri, "456") val response = testService.getRequestWithDynamicUri(dynamicUri, "456")
val request = server.takeRequest() val request = server.takeRequest()
assertThat(response.orElse("empty")).isEqualTo("Hello Spring!") assertThat(response.orElse("empty")).isEqualTo("Hello Spring!")
assertThat(request.method).isEqualTo("GET") assertThat(request.method).isEqualTo("GET")
assertThat(request.requestUrl.uri()).isEqualTo(dynamicUri) assertThat(request.requestUrl.uri()).isEqualTo(dynamicUri)
} }
@Test @Test
@Throws(InterruptedException::class) @Throws(InterruptedException::class)
fun postWithRequestHeader() { fun postWithRequestHeader() {
testService.postRequestWithHeader("testHeader", "testBody") testService.postRequestWithHeader("testHeader", "testBody")
val request = server.takeRequest() val request = server.takeRequest()
assertThat(request.method).isEqualTo("POST") assertThat(request.method).isEqualTo("POST")
assertThat(request.path).isEqualTo("/test") assertThat(request.path).isEqualTo("/test")
assertThat(request.headers["testHeaderName"]).isEqualTo("testHeader") assertThat(request.headers["testHeaderName"]).isEqualTo("testHeader")
assertThat(request.body.readUtf8()).isEqualTo("testBody") assertThat(request.body.readUtf8()).isEqualTo("testBody")
} }
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun formData() { fun formData() {
val map: MultiValueMap<String, String> = LinkedMultiValueMap() val map: MultiValueMap<String, String> = LinkedMultiValueMap()
map.add("param1", "value 1") map.add("param1", "value 1")
map.add("param2", "value 2") map.add("param2", "value 2")
testService.postForm(map) testService.postForm(map)
val request = server.takeRequest() val request = server.takeRequest()
assertThat(request.headers["Content-Type"]) assertThat(request.headers["Content-Type"])
.isEqualTo("application/x-www-form-urlencoded;charset=UTF-8") .isEqualTo("application/x-www-form-urlencoded;charset=UTF-8")
assertThat(request.body.readUtf8()).isEqualTo("param1=value+1&param2=value+2") assertThat(request.body.readUtf8()).isEqualTo("param1=value+1&param2=value+2")
} }
// gh-30342 // gh-30342
@Test @Test
@Throws(InterruptedException::class) @Throws(InterruptedException::class)
fun multipart() { fun multipart() {
val fileName = "testFileName" val fileName = "testFileName"
val originalFileName = "originalTestFileName" val originalFileName = "originalTestFileName"
val file: MultipartFile = MockMultipartFile(fileName, originalFileName, MediaType.APPLICATION_JSON_VALUE, val file: MultipartFile = MockMultipartFile(fileName, originalFileName, MediaType.APPLICATION_JSON_VALUE,
"test".toByteArray()) "test".toByteArray())
testService.postMultipart(file, "test2") testService.postMultipart(file, "test2")
val request = server.takeRequest() val request = server.takeRequest()
assertThat(request.headers["Content-Type"]).startsWith("multipart/form-data;boundary=") assertThat(request.headers["Content-Type"]).startsWith("multipart/form-data;boundary=")
assertThat(request.body.readUtf8()).containsSubsequence( assertThat(request.body.readUtf8()).containsSubsequence(
"Content-Disposition: form-data; name=\"file\"; filename=\"originalTestFileName\"", "Content-Disposition: form-data; name=\"file\"; filename=\"originalTestFileName\"",
"Content-Type: application/json", "Content-Length: 4", "test", "Content-Type: application/json", "Content-Length: 4", "test",
"Content-Disposition: form-data; name=\"anotherPart\"", "Content-Type: text/plain;charset=UTF-8", "Content-Disposition: form-data; name=\"anotherPart\"", "Content-Type: text/plain;charset=UTF-8",
"Content-Length: 5", "test2") "Content-Length: 5", "test2")
} }
@Test @Test
@Throws(InterruptedException::class) @Throws(InterruptedException::class)
fun putRequestWithCookies() { fun putRequestWithCookies() {
testService.putRequestWithCookies("test1", "test2") testService.putRequestWithCookies("test1", "test2")
val request = server.takeRequest() val request = server.takeRequest()
assertThat(request.method).isEqualTo("PUT") assertThat(request.method).isEqualTo("PUT")
assertThat(request.getHeader("Cookie")) assertThat(request.getHeader("Cookie"))
.isEqualTo("firstCookie=test1; secondCookie=test2") .isEqualTo("firstCookie=test1; secondCookie=test2")
} }
@Test @Test
@Throws(InterruptedException::class) @Throws(InterruptedException::class)
fun putRequestWithSameNameCookies() { fun putRequestWithSameNameCookies() {
testService.putRequestWithSameNameCookies("test1", "test2") testService.putRequestWithSameNameCookies("test1", "test2")
val request = server.takeRequest() val request = server.takeRequest()
assertThat(request.method).isEqualTo("PUT") assertThat(request.method).isEqualTo("PUT")
assertThat(request.getHeader("Cookie")) assertThat(request.getHeader("Cookie"))
.isEqualTo("testCookie=test1; testCookie=test2") .isEqualTo("testCookie=test1; testCookie=test2")
} }
@Test @Test
@Throws(InterruptedException::class) @Throws(InterruptedException::class)
@ -237,11 +237,11 @@ class KotlinRestTemplateHttpServiceProxyTests {
} }
private fun prepareResponse() { private fun prepareResponse() {
val response = MockResponse() val response = MockResponse()
response.setHeader("Content-Type", "text/plain").setBody("Hello Spring!") response.setHeader("Content-Type", "text/plain").setBody("Hello Spring!")
server.enqueue(response) server.enqueue(response)
} }
private fun anotherServer(): MockWebServer { private fun anotherServer(): MockWebServer {
val anotherServer = MockWebServer() val anotherServer = MockWebServer()
@ -251,34 +251,34 @@ class KotlinRestTemplateHttpServiceProxyTests {
return anotherServer return anotherServer
} }
private interface TestService { private interface TestService {
@get:GetExchange("/test") @get:GetExchange("/test")
val request: String val request: String
@GetExchange("/test/{id}") @GetExchange("/test/{id}")
fun getRequestWithPathVariable(@PathVariable id: String): ResponseEntity<String> fun getRequestWithPathVariable(@PathVariable id: String): ResponseEntity<String>
@GetExchange("/test/{id}") @GetExchange("/test/{id}")
fun getRequestWithDynamicUri(@Nullable uri: URI, @PathVariable id: String): Optional<String> fun getRequestWithDynamicUri(@Nullable uri: URI, @PathVariable id: String): Optional<String>
@PostExchange("/test") @PostExchange("/test")
fun postRequestWithHeader(@RequestHeader("testHeaderName") testHeader: String, fun postRequestWithHeader(@RequestHeader("testHeaderName") testHeader: String,
@RequestBody requestBody: String) @RequestBody requestBody: String)
@PostExchange(contentType = "application/x-www-form-urlencoded") @PostExchange(contentType = "application/x-www-form-urlencoded")
fun postForm(@RequestParam params: MultiValueMap<String, String>) fun postForm(@RequestParam params: MultiValueMap<String, String>)
@PostExchange @PostExchange
fun postMultipart(file: MultipartFile, @RequestPart anotherPart: String) fun postMultipart(file: MultipartFile, @RequestPart anotherPart: String)
@PutExchange @PutExchange
fun putRequestWithCookies(@CookieValue firstCookie: String, fun putRequestWithCookies(@CookieValue firstCookie: String,
@CookieValue secondCookie: String) @CookieValue secondCookie: String)
@PutExchange @PutExchange
fun putRequestWithSameNameCookies(@CookieValue("testCookie") firstCookie: String, fun putRequestWithSameNameCookies(@CookieValue("testCookie") firstCookie: String,
@CookieValue("testCookie") secondCookie: String) @CookieValue("testCookie") secondCookie: String)
@GetExchange("/greeting") @GetExchange("/greeting")
fun getWithUriBuilderFactory(uriBuilderFactory: UriBuilderFactory?): ResponseEntity<String> fun getWithUriBuilderFactory(uriBuilderFactory: UriBuilderFactory?): ResponseEntity<String>
@ -289,6 +289,6 @@ class KotlinRestTemplateHttpServiceProxyTests {
@GetExchange("/greeting") @GetExchange("/greeting")
fun getWithIgnoredUriBuilderFactory(uri: URI?, uriBuilderFactory: UriBuilderFactory?): ResponseEntity<String> fun getWithIgnoredUriBuilderFactory(uri: URI?, uriBuilderFactory: UriBuilderFactory?): ResponseEntity<String>
} }
} }

View File

@ -69,43 +69,43 @@ class KotlinHttpServiceMethodTests {
verifyClientInvocation("exchangeForEntityFlux", object : ParameterizedTypeReference<String>() {}) verifyClientInvocation("exchangeForEntityFlux", object : ParameterizedTypeReference<String>() {})
} }
@Test @Test
fun blockingServiceWithExchangeResponseFunction() { fun blockingServiceWithExchangeResponseFunction() {
val service = proxyFactory.createClient(BlockingFunctionsService::class.java) val service = proxyFactory.createClient(BlockingFunctionsService::class.java)
val stringBody = service.stringBodyBlocking() val stringBody = service.stringBodyBlocking()
assertThat(stringBody).isEqualTo("exchangeForBody") assertThat(stringBody).isEqualTo("exchangeForBody")
verifyTemplateInvocation("exchangeForBody", object : ParameterizedTypeReference<String>() {}) verifyTemplateInvocation("exchangeForBody", object : ParameterizedTypeReference<String>() {})
val listBody = service.listBodyBlocking() val listBody = service.listBodyBlocking()
assertThat(listBody.size).isEqualTo(1) assertThat(listBody.size).isEqualTo(1)
verifyTemplateInvocation("exchangeForBody", object : ParameterizedTypeReference<MutableList<String>>() {}) verifyTemplateInvocation("exchangeForBody", object : ParameterizedTypeReference<MutableList<String>>() {})
val stringEntity = service.stringEntityBlocking() val stringEntity = service.stringEntityBlocking()
assertThat(stringEntity).isEqualTo(ResponseEntity.ok<String>("exchangeForEntity")) assertThat(stringEntity).isEqualTo(ResponseEntity.ok<String>("exchangeForEntity"))
verifyTemplateInvocation("exchangeForEntity", object : ParameterizedTypeReference<String>() {}) verifyTemplateInvocation("exchangeForEntity", object : ParameterizedTypeReference<String>() {})
service.listEntityBlocking() service.listEntityBlocking()
verifyTemplateInvocation("exchangeForEntity", object : ParameterizedTypeReference<MutableList<String>>() {}) verifyTemplateInvocation("exchangeForEntity", object : ParameterizedTypeReference<MutableList<String>>() {})
} }
@Test @Test
fun coroutineServiceWithExchangeResponseFunction() { fun coroutineServiceWithExchangeResponseFunction() {
assertThatIllegalStateException().isThrownBy { assertThatIllegalStateException().isThrownBy {
proxyFactory.createClient(FunctionsService::class.java) proxyFactory.createClient(FunctionsService::class.java)
} }
assertThatIllegalStateException().isThrownBy { assertThatIllegalStateException().isThrownBy {
proxyFactory.createClient(SuspendingFunctionsService::class.java) proxyFactory.createClient(SuspendingFunctionsService::class.java)
} }
} }
private fun verifyTemplateInvocation(methodReference: String, expectedBodyType: ParameterizedTypeReference<*>) { private fun verifyTemplateInvocation(methodReference: String, expectedBodyType: ParameterizedTypeReference<*>) {
assertThat(exchangeAdapter.invokedMethodName).isEqualTo(methodReference) assertThat(exchangeAdapter.invokedMethodName).isEqualTo(methodReference)
assertThat(exchangeAdapter.bodyType).isEqualTo(expectedBodyType) assertThat(exchangeAdapter.bodyType).isEqualTo(expectedBodyType)
} }
private fun verifyClientInvocation(methodReference: String, expectedBodyType: ParameterizedTypeReference<*>) { private fun verifyClientInvocation(methodReference: String, expectedBodyType: ParameterizedTypeReference<*>) {
assertThat(reactorExchangeAdapter.invokedMethodName).isEqualTo(methodReference) assertThat(reactorExchangeAdapter.invokedMethodName).isEqualTo(methodReference)
assertThat(reactorExchangeAdapter.bodyType).isEqualTo(expectedBodyType) assertThat(reactorExchangeAdapter.bodyType).isEqualTo(expectedBodyType)
} }
@ -119,35 +119,35 @@ class KotlinHttpServiceMethodTests {
fun flowEntity(): ResponseEntity<Flow<String>> fun flowEntity(): ResponseEntity<Flow<String>>
} }
private interface SuspendingFunctionsService : BlockingFunctionsService { private interface SuspendingFunctionsService : BlockingFunctionsService {
@GetExchange @GetExchange
suspend fun stringBody(): String suspend fun stringBody(): String
@GetExchange @GetExchange
suspend fun listBody(): MutableList<String> suspend fun listBody(): MutableList<String>
@GetExchange @GetExchange
suspend fun stringEntity(): ResponseEntity<String> suspend fun stringEntity(): ResponseEntity<String>
@GetExchange @GetExchange
suspend fun listEntity(): ResponseEntity<MutableList<String>> suspend fun listEntity(): ResponseEntity<MutableList<String>>
} }
private interface BlockingFunctionsService { private interface BlockingFunctionsService {
@GetExchange @GetExchange
fun stringBodyBlocking(): String fun stringBodyBlocking(): String
@GetExchange @GetExchange
fun listBodyBlocking(): MutableList<String> fun listBodyBlocking(): MutableList<String>
@GetExchange @GetExchange
fun stringEntityBlocking(): ResponseEntity<String> fun stringEntityBlocking(): ResponseEntity<String>
@GetExchange @GetExchange
fun listEntityBlocking(): ResponseEntity<MutableList<String>> fun listEntityBlocking(): ResponseEntity<MutableList<String>>
} }
} }

View File

@ -90,8 +90,8 @@ suspend fun RequestHeadersSpec<out RequestHeadersSpec<*>>.awaitExchange(): Clien
* @since 5.3 * @since 5.3
*/ */
suspend fun <T: Any> RequestHeadersSpec<out RequestHeadersSpec<*>>.awaitExchange(responseHandler: suspend (ClientResponse) -> T): T { suspend fun <T: Any> RequestHeadersSpec<out RequestHeadersSpec<*>>.awaitExchange(responseHandler: suspend (ClientResponse) -> T): T {
val context = currentCoroutineContext().minusKey(Job.Key) val context = currentCoroutineContext().minusKey(Job.Key)
return exchangeToMono { mono(context) { responseHandler.invoke(it) } }.awaitSingle() return exchangeToMono { mono(context) { responseHandler.invoke(it) } }.awaitSingle()
} }
/** /**
@ -100,7 +100,7 @@ suspend fun <T: Any> RequestHeadersSpec<out RequestHeadersSpec<*>>.awaitExchange
* @since 5.3.8 * @since 5.3.8
*/ */
suspend fun <T: Any> RequestHeadersSpec<out RequestHeadersSpec<*>>.awaitExchangeOrNull(responseHandler: suspend (ClientResponse) -> T?): T? { suspend fun <T: Any> RequestHeadersSpec<out RequestHeadersSpec<*>>.awaitExchangeOrNull(responseHandler: suspend (ClientResponse) -> T?): T? {
val context = currentCoroutineContext().minusKey(Job.Key) val context = currentCoroutineContext().minusKey(Job.Key)
return exchangeToMono { mono(context) { responseHandler.invoke(it) } }.awaitSingleOrNull() return exchangeToMono { mono(context) { responseHandler.invoke(it) } }.awaitSingleOrNull()
} }

View File

@ -88,4 +88,4 @@ suspend fun ServerWebExchange.awaitSession(): WebSession =
ReplaceWith("principal(supplier)", "org.springframework.web.server.principal"), ReplaceWith("principal(supplier)", "org.springframework.web.server.principal"),
) )
fun ServerWebExchange.Builder.principal(supplier: suspend () -> Principal): ServerWebExchange.Builder fun ServerWebExchange.Builder.principal(supplier: suspend () -> Principal): ServerWebExchange.Builder
= principal(mono(Dispatchers.Unconfined) { supplier.invoke() }) = principal(mono(Dispatchers.Unconfined) { supplier.invoke() })