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

View File

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

View File

@ -45,99 +45,99 @@ import javax.lang.model.element.Modifier
*/
class InstanceSupplierCodeGeneratorKotlinTests {
private val generationContext = TestGenerationContext()
private val generationContext = TestGenerationContext()
@Test
fun generateWhenHasDefaultConstructor() {
val beanDefinition: BeanDefinition = RootBeanDefinition(KotlinTestBean::class.java)
val beanFactory = DefaultListableBeanFactory()
compile(beanFactory, beanDefinition) { instanceSupplier, compiled ->
val bean = getBean<KotlinTestBean>(beanFactory, beanDefinition, instanceSupplier)
Assertions.assertThat(bean).isInstanceOf(KotlinTestBean::class.java)
Assertions.assertThat(compiled.sourceFile).contains("InstanceSupplier.using(KotlinTestBean::new)")
}
Assertions.assertThat(getReflectionHints().getTypeHint(KotlinTestBean::class.java))
.satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT))
}
@Test
fun generateWhenHasDefaultConstructor() {
val beanDefinition: BeanDefinition = RootBeanDefinition(KotlinTestBean::class.java)
val beanFactory = DefaultListableBeanFactory()
compile(beanFactory, beanDefinition) { instanceSupplier, compiled ->
val bean = getBean<KotlinTestBean>(beanFactory, beanDefinition, instanceSupplier)
Assertions.assertThat(bean).isInstanceOf(KotlinTestBean::class.java)
Assertions.assertThat(compiled.sourceFile).contains("InstanceSupplier.using(KotlinTestBean::new)")
}
Assertions.assertThat(getReflectionHints().getTypeHint(KotlinTestBean::class.java))
.satisfies(hasConstructorWithMode(ExecutableMode.INTROSPECT))
}
@Test
fun generateWhenConstructorHasOptionalParameter() {
val beanDefinition: BeanDefinition = RootBeanDefinition(KotlinTestBeanWithOptionalParameter::class.java)
val beanFactory = DefaultListableBeanFactory()
compile(beanFactory, beanDefinition) { instanceSupplier, compiled ->
val bean: KotlinTestBeanWithOptionalParameter = getBean(beanFactory, beanDefinition, instanceSupplier)
Assertions.assertThat(bean).isInstanceOf(KotlinTestBeanWithOptionalParameter::class.java)
Assertions.assertThat(compiled.sourceFile)
.contains("return BeanInstanceSupplier.<KotlinTestBeanWithOptionalParameter>forConstructor();")
}
Assertions.assertThat<TypeHint>(getReflectionHints().getTypeHint(KotlinTestBeanWithOptionalParameter::class.java))
.satisfies(hasMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS))
}
@Test
fun generateWhenConstructorHasOptionalParameter() {
val beanDefinition: BeanDefinition = RootBeanDefinition(KotlinTestBeanWithOptionalParameter::class.java)
val beanFactory = DefaultListableBeanFactory()
compile(beanFactory, beanDefinition) { instanceSupplier, compiled ->
val bean: KotlinTestBeanWithOptionalParameter = getBean(beanFactory, beanDefinition, instanceSupplier)
Assertions.assertThat(bean).isInstanceOf(KotlinTestBeanWithOptionalParameter::class.java)
Assertions.assertThat(compiled.sourceFile)
.contains("return BeanInstanceSupplier.<KotlinTestBeanWithOptionalParameter>forConstructor();")
}
Assertions.assertThat<TypeHint>(getReflectionHints().getTypeHint(KotlinTestBeanWithOptionalParameter::class.java))
.satisfies(hasMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS))
}
private fun getReflectionHints(): ReflectionHints {
return generationContext.runtimeHints.reflection()
}
private fun getReflectionHints(): ReflectionHints {
return generationContext.runtimeHints.reflection()
}
private fun hasConstructorWithMode(mode: ExecutableMode): ThrowingConsumer<TypeHint> {
return ThrowingConsumer {
Assertions.assertThat(it.constructors()).anySatisfy(hasMode(mode))
}
}
private fun hasConstructorWithMode(mode: ExecutableMode): ThrowingConsumer<TypeHint> {
return ThrowingConsumer {
Assertions.assertThat(it.constructors()).anySatisfy(hasMode(mode))
}
}
private fun hasMemberCategory(category: MemberCategory): ThrowingConsumer<TypeHint> {
return ThrowingConsumer {
Assertions.assertThat(it.memberCategories).contains(category)
}
}
private fun hasMemberCategory(category: MemberCategory): ThrowingConsumer<TypeHint> {
return ThrowingConsumer {
Assertions.assertThat(it.memberCategories).contains(category)
}
}
private fun hasMode(mode: ExecutableMode): ThrowingConsumer<ExecutableHint> {
return ThrowingConsumer {
Assertions.assertThat(it.mode).isEqualTo(mode)
}
}
private fun hasMode(mode: ExecutableMode): ThrowingConsumer<ExecutableHint> {
return ThrowingConsumer {
Assertions.assertThat(it.mode).isEqualTo(mode)
}
}
@Suppress("UNCHECKED_CAST")
private fun <T> getBean(beanFactory: DefaultListableBeanFactory, beanDefinition: BeanDefinition,
instanceSupplier: InstanceSupplier<*>): T {
(beanDefinition as RootBeanDefinition).instanceSupplier = instanceSupplier
beanFactory.registerBeanDefinition("testBean", beanDefinition)
return beanFactory.getBean("testBean") as T
}
@Suppress("UNCHECKED_CAST")
private fun <T> getBean(beanFactory: DefaultListableBeanFactory, beanDefinition: BeanDefinition,
instanceSupplier: InstanceSupplier<*>): T {
(beanDefinition as RootBeanDefinition).instanceSupplier = instanceSupplier
beanFactory.registerBeanDefinition("testBean", beanDefinition)
return beanFactory.getBean("testBean") as T
}
private fun compile(beanFactory: DefaultListableBeanFactory, beanDefinition: BeanDefinition,
result: BiConsumer<InstanceSupplier<*>, Compiled>) {
private fun compile(beanFactory: DefaultListableBeanFactory, beanDefinition: BeanDefinition,
result: BiConsumer<InstanceSupplier<*>, Compiled>) {
val freshBeanFactory = DefaultListableBeanFactory(beanFactory)
freshBeanFactory.registerBeanDefinition("testBean", beanDefinition)
val registeredBean = RegisteredBean.of(freshBeanFactory, "testBean")
val typeBuilder = DeferredTypeBuilder()
val generateClass = generationContext.generatedClasses.addForFeature("TestCode", typeBuilder)
val generator = InstanceSupplierCodeGenerator(
generationContext, generateClass.name,
generateClass.methods, false
)
val instantiationDescriptor = registeredBean.resolveInstantiationDescriptor()
Assertions.assertThat(instantiationDescriptor).isNotNull()
val generatedCode = generator.generateCode(registeredBean, instantiationDescriptor)
typeBuilder.set { type: TypeSpec.Builder ->
type.addModifiers(Modifier.PUBLIC)
type.addSuperinterface(
ParameterizedTypeName.get(
Supplier::class.java,
InstanceSupplier::class.java
)
)
type.addMethod(
MethodSpec.methodBuilder("get")
.addModifiers(Modifier.PUBLIC)
.returns(InstanceSupplier::class.java)
.addStatement("return \$L", generatedCode).build()
)
}
generationContext.writeGeneratedContent()
TestCompiler.forSystem().with(generationContext).compile {
result.accept(it.getInstance(Supplier::class.java).get() as InstanceSupplier<*>, it)
}
}
val freshBeanFactory = DefaultListableBeanFactory(beanFactory)
freshBeanFactory.registerBeanDefinition("testBean", beanDefinition)
val registeredBean = RegisteredBean.of(freshBeanFactory, "testBean")
val typeBuilder = DeferredTypeBuilder()
val generateClass = generationContext.generatedClasses.addForFeature("TestCode", typeBuilder)
val generator = InstanceSupplierCodeGenerator(
generationContext, generateClass.name,
generateClass.methods, false
)
val instantiationDescriptor = registeredBean.resolveInstantiationDescriptor()
Assertions.assertThat(instantiationDescriptor).isNotNull()
val generatedCode = generator.generateCode(registeredBean, instantiationDescriptor)
typeBuilder.set { type: TypeSpec.Builder ->
type.addModifiers(Modifier.PUBLIC)
type.addSuperinterface(
ParameterizedTypeName.get(
Supplier::class.java,
InstanceSupplier::class.java
)
)
type.addMethod(
MethodSpec.methodBuilder("get")
.addModifiers(Modifier.PUBLIC)
.returns(InstanceSupplier::class.java)
.addStatement("return \$L", generatedCode).build()
)
}
generationContext.writeGeneratedContent()
TestCompiler.forSystem().with(generationContext).compile {
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 {
private val processor = BeanValidationBeanRegistrationAotProcessor()
private val processor = BeanValidationBeanRegistrationAotProcessor()
private val generationContext: GenerationContext = TestGenerationContext()
private val generationContext: GenerationContext = TestGenerationContext()
@Test
fun shouldProcessMethodParameterLevelConstraint() {
process(MethodParameterLevelConstraint::class.java)
Assertions.assertThat(
RuntimeHintsPredicates.reflection().onType(ExistsValidator::class.java)
.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)
).accepts(generationContext.runtimeHints)
}
@Test
fun shouldProcessMethodParameterLevelConstraint() {
process(MethodParameterLevelConstraint::class.java)
Assertions.assertThat(
RuntimeHintsPredicates.reflection().onType(ExistsValidator::class.java)
.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)
).accepts(generationContext.runtimeHints)
}
@Test
fun shouldSkipMethodParameterLevelConstraintWihExtension() {
process(MethodParameterLevelConstraintWithExtension::class.java)
Assertions.assertThat(generationContext.runtimeHints.reflection().typeHints()).isEmpty()
}
@Test
fun shouldSkipMethodParameterLevelConstraintWihExtension() {
process(MethodParameterLevelConstraintWithExtension::class.java)
Assertions.assertThat(generationContext.runtimeHints.reflection().typeHints()).isEmpty()
}
private fun process(beanClass: Class<*>) {
val contribution = createContribution(beanClass)
contribution?.applyTo(generationContext, Mockito.mock())
}
private fun process(beanClass: Class<*>) {
val contribution = createContribution(beanClass)
contribution?.applyTo(generationContext, Mockito.mock())
}
private fun createContribution(beanClass: Class<*>): BeanRegistrationAotContribution? {
val beanFactory = DefaultListableBeanFactory()
beanFactory.registerBeanDefinition(beanClass.name, RootBeanDefinition(beanClass))
return processor.processAheadOfTime(RegisteredBean.of(beanFactory, beanClass.name))
}
private fun createContribution(beanClass: Class<*>): BeanRegistrationAotContribution? {
val beanFactory = DefaultListableBeanFactory()
beanFactory.registerBeanDefinition(beanClass.name, RootBeanDefinition(beanClass))
return processor.processAheadOfTime(RegisteredBean.of(beanFactory, beanClass.name))
}
internal class MethodParameterLevelConstraintWithExtension {
internal class MethodParameterLevelConstraintWithExtension {
@Suppress("unused")
fun hello(name: @Exists String): String {
return name.toHello()
}
@Suppress("unused")
fun hello(name: @Exists String): String {
return name.toHello()
}
private fun String.toHello() =
"Hello $this"
}
private fun String.toHello() =
"Hello $this"
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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