mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a04435cd0 | |||
| b7e99fbe30 | |||
| a27f2e994b | |||
| 284cf3ecf2 | |||
| cbf25b704d | |||
| 8391897a94 | |||
| a3c89092e1 | |||
| e77c426eeb |
@@ -20,6 +20,9 @@ Feel free to join the #spring channel of https://slack.kotlinlang.org/[Kotlin Sl
|
||||
or ask a question with `spring` and `kotlin` as tags on
|
||||
https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you need support.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-requirements]]
|
||||
== Requirements
|
||||
|
||||
@@ -37,6 +40,9 @@ for serializing or deserializing JSON data for Kotlin classes with Jackson, so m
|
||||
`com.fasterxml.jackson.module:jackson-module-kotlin` dependency to your project if you have such need.
|
||||
It is automatically registered when found in the classpath.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-extensions]]
|
||||
== Extensions
|
||||
|
||||
@@ -80,6 +86,9 @@ With Kotlin and the Spring Framework extensions, you can instead write the follo
|
||||
As in Java, `users` in Kotlin is strongly typed, but Kotlin's clever type inference allows
|
||||
for shorter syntax.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-null-safety]]
|
||||
== Null-safety
|
||||
|
||||
@@ -115,6 +124,9 @@ NOTE: Generic type arguments, varargs, and array elements nullability are not su
|
||||
but should be in an upcoming release. See https://github.com/Kotlin/KEEP/issues/79[this discussion]
|
||||
for up-to-date information.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-classes-interfaces]]
|
||||
== Classes and Interfaces
|
||||
|
||||
@@ -124,12 +136,16 @@ with default values.
|
||||
|
||||
Kotlin parameter names are recognized through a dedicated `KotlinReflectionParameterNameDiscoverer`,
|
||||
which allows finding interface method parameter names without requiring the Java 8 `-parameters`
|
||||
compiler flag to be enabled during compilation.
|
||||
compiler flag to be enabled during compilation. (For completeness, we nevertheless recommend
|
||||
running the Kotlin compiler with its `-java-parameters` flag for standard Java parameter exposure.)
|
||||
|
||||
You can declare configuration classes as
|
||||
https://kotlinlang.org/docs/reference/nested-classes.html[top level or nested but not inner],
|
||||
since the later requires a reference to the outer class.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-annotations]]
|
||||
== Annotations
|
||||
|
||||
@@ -156,6 +172,9 @@ https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targe
|
||||
such as `@field:NotNull` or `@get:Size(min=5, max=15)`, as described in
|
||||
https://stackoverflow.com/a/35853200/1092077[this Stack Overflow response].
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-bean-definition-dsl]]
|
||||
== Bean Definition DSL
|
||||
|
||||
@@ -263,16 +282,20 @@ as the following example shows:
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
NOTE: Spring Boot is based on JavaConfig and
|
||||
https://github.com/spring-projects/spring-boot/issues/8115[does not yet provide specific support for functional bean definition],
|
||||
but you can experimentally use functional bean definitions through Spring Boot's `ApplicationContextInitializer` support.
|
||||
See https://stackoverflow.com/questions/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer]
|
||||
for more details and up-to-date information. See also the experimental Kofu DSL developed in https://github.com/spring-projects/spring-fu[Spring Fu incubator].
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-web]]
|
||||
== Web
|
||||
|
||||
|
||||
|
||||
=== Router DSL
|
||||
|
||||
Spring Framework comes with a Kotlin router DSL available in 3 flavors:
|
||||
@@ -314,6 +337,8 @@ when you need to register routes depending on dynamic data (for example, from a
|
||||
|
||||
See https://github.com/mixitconf/mixit/[MiXiT project] for a concrete example.
|
||||
|
||||
|
||||
|
||||
=== MockMvc DSL
|
||||
|
||||
A Kotlin DSL is provided via `MockMvc` Kotlin extensions in order to provide a more
|
||||
@@ -339,6 +364,8 @@ mockMvc.get("/person/{name}", "Lee") {
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== Kotlin Script Templates
|
||||
|
||||
Spring Framework provides a
|
||||
@@ -357,9 +384,7 @@ dependencies {
|
||||
}
|
||||
----
|
||||
|
||||
Configuration is usually done with `ScriptTemplateConfigurer` and `ScriptTemplateViewResolver`
|
||||
beans.
|
||||
|
||||
Configuration is usually done with `ScriptTemplateConfigurer` and `ScriptTemplateViewResolver` beans.
|
||||
|
||||
`KotlinScriptConfiguration.kt`
|
||||
[source,kotlin,indent=0]
|
||||
@@ -386,6 +411,8 @@ class KotlinScriptConfiguration {
|
||||
See the https://github.com/sdeleuze/kotlin-script-templating[kotlin-script-templating] example
|
||||
project for more details.
|
||||
|
||||
|
||||
|
||||
=== Kotlin multiplatform serialization
|
||||
|
||||
As of Spring Framework 5.3, https://github.com/Kotlin/kotlinx.serialization[Kotlin multiplatform serialization] is
|
||||
@@ -397,6 +424,9 @@ Kotlin serialization is designed to serialize only Kotlin classes annotated with
|
||||
With Spring Messaging (RSocket), make sure that neither Jackson, GSON or JSONB are in the classpath if you want automatic configuration,
|
||||
if Jackson is needed configure `KotlinSerializationJsonMessageConverter` manually.
|
||||
|
||||
|
||||
|
||||
|
||||
== Coroutines
|
||||
|
||||
Kotlin https://kotlinlang.org/docs/reference/coroutines-overview.html[Coroutines] are Kotlin
|
||||
@@ -415,6 +445,8 @@ Spring Framework provides support for Coroutines on the following scope:
|
||||
* Suspending function and `Flow` support in RSocket `@MessageMapping` annotated methods
|
||||
* Extensions for {docs-spring-framework}/kdoc-api/spring-messaging/org.springframework.messaging.rsocket/index.html[`RSocketRequester`]
|
||||
|
||||
|
||||
|
||||
=== Dependencies
|
||||
|
||||
Coroutines support is enabled when `kotlinx-coroutines-core` and `kotlinx-coroutines-reactor`
|
||||
@@ -432,6 +464,8 @@ dependencies {
|
||||
|
||||
Version `1.4.0` and above are supported.
|
||||
|
||||
|
||||
|
||||
=== How Reactive translates to Coroutines?
|
||||
|
||||
For return values, the translation from Reactive to Coroutines APIs is the following:
|
||||
@@ -458,6 +492,8 @@ https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coro
|
||||
Read this blog post about https://spring.io/blog/2019/04/12/going-reactive-with-spring-coroutines-and-kotlin-flow[Going Reactive with Spring, Coroutines and Kotlin Flow]
|
||||
for more details, including how to run code concurrently with Coroutines.
|
||||
|
||||
|
||||
|
||||
=== Controllers
|
||||
|
||||
Here is an example of a Coroutines `@RestController`.
|
||||
@@ -554,6 +590,8 @@ class CoroutinesViewController(banner: Banner) {
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== WebFlux.fn
|
||||
|
||||
Here is an example of Coroutines router defined via the {docs-spring-framework}/kdoc-api/spring-webflux/org.springframework.web.reactive.function.server/co-router.html[coRouter { }] DSL and related handlers.
|
||||
@@ -587,6 +625,8 @@ class UserHandler(builder: WebClient.Builder) {
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== Transactions
|
||||
|
||||
Transactions on Coroutines are supported via the programmatic variant of the Reactive
|
||||
@@ -636,6 +676,8 @@ For Kotlin `Flow`, a `Flow<T>.transactional` extension is provided.
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-spring-projects-in-kotlin]]
|
||||
== Spring Projects in Kotlin
|
||||
|
||||
@@ -683,6 +725,8 @@ NOTE: The Kotlin code samples in Spring Framework documentation do not explicitl
|
||||
`open` on the classes and their member functions. The samples are written for projects
|
||||
using the `kotlin-allopen` plugin, since this is the most commonly used setup.
|
||||
|
||||
|
||||
|
||||
=== Using Immutable Class Instances for Persistence
|
||||
|
||||
In Kotlin, it is convenient and considered to be a best practice to declare read-only properties
|
||||
@@ -726,6 +770,8 @@ NOTE: As of the Kay release train, Spring Data supports Kotlin immutable class i
|
||||
does not require the `kotlin-noarg` plugin if the module uses Spring Data object mappings
|
||||
(such as MongoDB, Redis, Cassandra, and others).
|
||||
|
||||
|
||||
|
||||
=== Injecting Dependencies
|
||||
|
||||
Our recommendation is to try to favor constructor injection with `val` read-only (and
|
||||
@@ -761,6 +807,8 @@ as the following example shows:
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== Injecting Configuration Properties
|
||||
|
||||
In Java, you can inject configuration properties by using annotations (such as pass:q[`@Value("${property}")`)].
|
||||
@@ -801,6 +849,7 @@ that uses the `${...}` syntax, with configuration beans, as the following exampl
|
||||
----
|
||||
|
||||
|
||||
|
||||
=== Checked Exceptions
|
||||
|
||||
Java and https://kotlinlang.org/docs/reference/exceptions.html[Kotlin exception handling]
|
||||
@@ -813,6 +862,8 @@ To get the original exception thrown like in Java, methods should be annotated w
|
||||
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/index.html[`@Throws`]
|
||||
to specify explicitly the checked exceptions thrown (for example `@Throws(IOException::class)`).
|
||||
|
||||
|
||||
|
||||
=== Annotation Array Attributes
|
||||
|
||||
Kotlin annotations are mostly similar to Java annotations, but array attributes (which are
|
||||
@@ -857,6 +908,8 @@ use a shortcut annotation, such as `@GetMapping`, `@PostMapping`, and others.
|
||||
NOTE: If the `@RequestMapping` `method` attribute is not specified, all HTTP methods will
|
||||
be matched, not only the `GET` method.
|
||||
|
||||
|
||||
|
||||
=== Testing
|
||||
|
||||
This section addresses testing with the combination of Kotlin and Spring Framework.
|
||||
@@ -866,6 +919,7 @@ https://mockk.io/[Mockk] for mocking.
|
||||
NOTE: If you are using Spring Boot, see
|
||||
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-kotlin-testing[this related documentation].
|
||||
|
||||
|
||||
==== Constructor injection
|
||||
|
||||
As described in the <<testing#testcontext-junit-jupiter-di, dedicated section>>,
|
||||
@@ -887,6 +941,7 @@ class OrderServiceIntegrationTests(val orderService: OrderService,
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
==== `PER_CLASS` Lifecycle
|
||||
|
||||
Kotlin lets you specify meaningful test function names between backticks (```).
|
||||
@@ -930,6 +985,7 @@ class IntegrationTests {
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
==== Specification-like Tests
|
||||
|
||||
You can create specification-like tests with JUnit 5 and Kotlin.
|
||||
@@ -959,6 +1015,7 @@ class SpecificationLikeTests {
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
[[kotlin-webtestclient-issue]]
|
||||
==== `WebTestClient` Type Inference Issue in Kotlin
|
||||
|
||||
@@ -968,17 +1025,24 @@ since it provides a workaround for the Kotlin issue with the Java API.
|
||||
|
||||
See also the related https://jira.spring.io/browse/SPR-16057[SPR-16057] issue.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-getting-started]]
|
||||
== Getting Started
|
||||
|
||||
The easiest way to learn how to build a Spring application with Kotlin is to follow
|
||||
https://spring.io/guides/tutorials/spring-boot-kotlin/[the dedicated tutorial].
|
||||
|
||||
|
||||
|
||||
=== `start.spring.io`
|
||||
|
||||
The easiest way to start a new Spring Framework project in Kotlin is to create a new Spring
|
||||
Boot 2 project on https://start.spring.io/#!language=kotlin&type=gradle-project[start.spring.io].
|
||||
|
||||
|
||||
|
||||
=== Choosing the Web Flavor
|
||||
|
||||
Spring Framework now comes with two different web stacks: <<web#mvc, Spring MVC>> and
|
||||
@@ -991,6 +1055,9 @@ Kotlin DSL.
|
||||
For other use cases, especially if you are using blocking technologies such as JPA, Spring
|
||||
MVC and its annotation-based programming model is the recommended choice.
|
||||
|
||||
|
||||
|
||||
|
||||
[[kotlin-resources]]
|
||||
== Resources
|
||||
|
||||
@@ -1004,6 +1071,8 @@ Kotlin and the Spring Framework:
|
||||
* https://blog.jetbrains.com/kotlin/[Kotlin blog]
|
||||
* https://kotlin.link/[Awesome Kotlin]
|
||||
|
||||
|
||||
|
||||
=== Examples
|
||||
|
||||
The following Github projects offer examples that you can learn from and possibly even extend:
|
||||
@@ -1016,6 +1085,8 @@ The following Github projects offer examples that you can learn from and possibl
|
||||
* https://github.com/sdeleuze/spring-kotlin-deepdive[spring-kotlin-deepdive]: A step-by-step migration guide for Boot 1.0 and Java to Boot 2.0 and Kotlin
|
||||
* https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-kotlin-samples/spring-cloud-gcp-kotlin-app-sample[spring-cloud-gcp-kotlin-app-sample]: Spring Boot with Google Cloud Platform Integrations
|
||||
|
||||
|
||||
|
||||
=== Issues
|
||||
|
||||
The following list categorizes the pending issues related to Spring and Kotlin support:
|
||||
|
||||
@@ -1141,9 +1141,10 @@ request with a simple request parameter.
|
||||
[.small]#<<web-reactive.adoc#webflux-multipart, WebFlux>>#
|
||||
|
||||
`MultipartResolver` from the `org.springframework.web.multipart` package is a strategy
|
||||
for parsing multipart requests including file uploads. There is one implementation
|
||||
based on https://commons.apache.org/proper/commons-fileupload[Commons FileUpload] and
|
||||
another based on Servlet multipart request parsing.
|
||||
for parsing multipart requests including file uploads. There is a container-based
|
||||
`StandardServletMultipartResolver` implementation for Servlet multipart request parsing.
|
||||
Note that the outdated `CommonsMultipartResolver` based on Apache Commons FileUpload is
|
||||
not available anymore, as of Spring Framework 6.0 with its new Servlet 5.0+ baseline.
|
||||
|
||||
To enable multipart handling, you need to declare a `MultipartResolver` bean in your
|
||||
`DispatcherServlet` Spring configuration with a name of `multipartResolver`.
|
||||
@@ -1153,26 +1154,6 @@ content wraps the current `HttpServletRequest` as a `MultipartHttpServletRequest
|
||||
provide access to resolved files in addition to exposing parts as request parameters.
|
||||
|
||||
|
||||
[[mvc-multipart-resolver-commons]]
|
||||
==== Apache Commons `FileUpload`
|
||||
|
||||
To use Apache Commons `FileUpload`, you can configure a bean of type
|
||||
`CommonsMultipartResolver` with a name of `multipartResolver`. You also need to have
|
||||
the `commons-fileupload` jar as a dependency on your classpath.
|
||||
|
||||
This resolver variant delegates to a local library within the application, providing
|
||||
maximum portability across Servlet containers. As an alternative, consider standard
|
||||
Servlet multipart resolution through the container's own parser as discussed below.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Commons FileUpload traditionally applies to POST requests only but accepts any
|
||||
`multipart/` content type. See the
|
||||
{api-spring-framework}/web/multipart/commons/CommonsMultipartResolver.html[`CommonsMultipartResolver`]
|
||||
javadoc for details and configuration options.
|
||||
====
|
||||
|
||||
|
||||
[[mvc-multipart-resolver-standard]]
|
||||
==== Servlet Multipart Parsing
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=6.0.1-SNAPSHOT
|
||||
version=6.0.2
|
||||
|
||||
org.gradle.caching=true
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
|
||||
+14
-3
@@ -49,7 +49,8 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
import org.springframework.core.KotlinReflectionParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -100,7 +101,7 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
private ConstraintValidatorFactory constraintValidatorFactory;
|
||||
|
||||
@Nullable
|
||||
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
|
||||
private ParameterNameDiscoverer parameterNameDiscoverer;
|
||||
|
||||
@Nullable
|
||||
private Resource[] mappingLocations;
|
||||
@@ -117,6 +118,13 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
private ValidatorFactory validatorFactory;
|
||||
|
||||
|
||||
public LocalValidatorFactoryBean() {
|
||||
if (KotlinDetector.isKotlinReflectPresent()) {
|
||||
this.parameterNameDiscoverer = new KotlinReflectionParameterNameDiscoverer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the desired provider class, if any.
|
||||
* <p>If not specified, JSR-303's default search mechanism will be used.
|
||||
@@ -188,7 +196,10 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
/**
|
||||
* Set the ParameterNameDiscoverer to use for resolving method and constructor
|
||||
* parameter names if needed for message interpolation.
|
||||
* <p>Default is a {@link org.springframework.core.DefaultParameterNameDiscoverer}.
|
||||
* <p>Default is Hibernate Validator's own internal use of standard Java reflection,
|
||||
* with an additional {@link KotlinReflectionParameterNameDiscoverer} if Kotlin
|
||||
* is present. This may be overridden with a custom subclass or a Spring-controlled
|
||||
* {@link org.springframework.core.DefaultParameterNameDiscoverer} if necessary,
|
||||
*/
|
||||
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
|
||||
this.parameterNameDiscoverer = parameterNameDiscoverer;
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,11 +30,13 @@ import org.springframework.lang.Nullable;
|
||||
* {@link ParameterNameDiscoverer} implementation which uses Kotlin's reflection facilities
|
||||
* for introspecting parameter names.
|
||||
*
|
||||
* Compared to {@link StandardReflectionParameterNameDiscoverer}, it allows in addition to
|
||||
* <p>Compared to {@link StandardReflectionParameterNameDiscoverer}, it allows in addition to
|
||||
* determine interface parameter names without requiring Java 8 -parameters compiler flag.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 5.0
|
||||
* @see StandardReflectionParameterNameDiscoverer
|
||||
* @see DefaultParameterNameDiscoverer
|
||||
*/
|
||||
public class KotlinReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
|
||||
+14
-6
@@ -47,12 +47,21 @@ import org.springframework.util.ClassUtils;
|
||||
* caches the ASM discovered information for each introspected Class, in a thread-safe
|
||||
* manner. It is recommended to reuse ParameterNameDiscoverer instances as far as possible.
|
||||
*
|
||||
* <p>This class is deprecated in the 6.0 generation and scheduled for removal in 6.1
|
||||
* since it is effectively superseded by {@link StandardReflectionParameterNameDiscoverer}.
|
||||
* For the time being, this discoverer logs a warning every time it actually inspects a
|
||||
* class file which is particularly useful for identifying remaining gaps in usage of
|
||||
* the standard "-parameters" compiler flag, and also unintended over-inspection of
|
||||
* e.g. JDK core library classes (which are not compiled with the "-parameters" flag).
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Sam Brannen
|
||||
* @since 2.0
|
||||
* @see StandardReflectionParameterNameDiscoverer
|
||||
* @see DefaultParameterNameDiscoverer
|
||||
* @deprecated as of 6.0.1, in favor of {@link StandardReflectionParameterNameDiscoverer}
|
||||
* (with the "-parameters" compiler flag)
|
||||
*/
|
||||
@@ -85,12 +94,7 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
|
||||
private String[] doGetParameterNames(Executable executable) {
|
||||
Class<?> declaringClass = executable.getDeclaringClass();
|
||||
Map<Executable, String[]> map = this.parameterNamesCache.computeIfAbsent(declaringClass, this::inspectClass);
|
||||
String[] names = (map != NO_DEBUG_INFO_MAP ? map.get(executable) : null);
|
||||
if (names != null && logger.isWarnEnabled()) {
|
||||
logger.warn("Using deprecated '-debug' fallback for parameter name resolution. " +
|
||||
"Compile the affected code with '-parameters' instead: " + executable);
|
||||
}
|
||||
return names;
|
||||
return (map != NO_DEBUG_INFO_MAP ? map.get(executable) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,6 +119,10 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
|
||||
ClassReader classReader = new ClassReader(is);
|
||||
Map<Executable, String[]> map = new ConcurrentHashMap<>(32);
|
||||
classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Using deprecated '-debug' fallback for parameter name resolution. Compile the " +
|
||||
"affected code with '-parameters' instead or avoid its introspection: " + clazz.getName());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
|
||||
+6
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,10 +26,15 @@ import org.springframework.lang.Nullable;
|
||||
* {@link ParameterNameDiscoverer} implementation which uses JDK 8's reflection facilities
|
||||
* for introspecting parameter names (based on the "-parameters" compiler flag).
|
||||
*
|
||||
* <p>This is a key element of {@link DefaultParameterNameDiscoverer} where it is being
|
||||
* combined with {@link KotlinReflectionParameterNameDiscoverer} if Kotlin is present.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @see java.lang.reflect.Method#getParameters()
|
||||
* @see java.lang.reflect.Parameter#getName()
|
||||
* @see KotlinReflectionParameterNameDiscoverer
|
||||
* @see DefaultParameterNameDiscoverer
|
||||
*/
|
||||
public class StandardReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
|
||||
+3
-3
@@ -442,7 +442,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Starting \"system\" session, " + toString());
|
||||
logger.info("Starting \"system\" session, " + this);
|
||||
}
|
||||
|
||||
StompHeaderAccessor accessor = StompHeaderAccessor.create(StompCommand.CONNECT);
|
||||
@@ -699,7 +699,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
@Override
|
||||
public void afterConnected(TcpConnection<byte[]> connection) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("TCP connection opened in session=" + getSessionId());
|
||||
logger.debug("TCP connection " + connection + " opened in session=" + getSessionId());
|
||||
}
|
||||
this.tcpConnection = connection;
|
||||
connection.onReadInactivity(() -> {
|
||||
@@ -978,7 +978,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||
this.tcpConnection = null;
|
||||
if (conn != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Closing TCP connection in session " + this.sessionId);
|
||||
logger.debug("Closing TCP connection " + conn + " in session " + this.sessionId);
|
||||
}
|
||||
conn.close();
|
||||
}
|
||||
|
||||
+4
@@ -81,4 +81,8 @@ public class ReactorNetty2TcpConnection<P> implements TcpConnection<P> {
|
||||
this.completionSink.tryEmitEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ReactorNetty2TcpConnection[inbound=" + this.inbound + "]";
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -80,4 +80,9 @@ public class ReactorNettyTcpConnection<P> implements TcpConnection<P> {
|
||||
this.completionSink.tryEmitEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ReactorNettyTcpConnection[inbound=" + this.inbound + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-2
@@ -56,8 +56,7 @@ public class MethodNotAllowedException extends ResponseStatusException {
|
||||
}
|
||||
this.method = method;
|
||||
this.httpMethods = Collections.unmodifiableSet(new LinkedHashSet<>(supportedMethods));
|
||||
getBody().setDetail(this.httpMethods.isEmpty() ?
|
||||
getReason() : "Supported methods: " + this.httpMethods);
|
||||
setDetail(this.httpMethods.isEmpty() ? getReason() : "Supported methods: " + this.httpMethods);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class MissingRequestValueException extends ServerWebInputException {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.label = label;
|
||||
getBody().setDetail(getReason());
|
||||
setDetail(getReason());
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ public class NotAcceptableStatusException extends ResponseStatusException {
|
||||
public NotAcceptableStatusException(String reason) {
|
||||
super(HttpStatus.NOT_ACCEPTABLE, reason, null, PARSE_ERROR_DETAIL_CODE, null);
|
||||
this.supportedMediaTypes = Collections.emptyList();
|
||||
getBody().setDetail("Could not parse Accept header.");
|
||||
setDetail("Could not parse Accept header.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,7 +58,7 @@ public class NotAcceptableStatusException extends ResponseStatusException {
|
||||
"Could not find acceptable representation", null, null, new Object[] {mediaTypes});
|
||||
|
||||
this.supportedMediaTypes = Collections.unmodifiableList(mediaTypes);
|
||||
getBody().setDetail("Acceptable representations: " + mediaTypes + ".");
|
||||
setDetail("Acceptable representations: " + mediaTypes + ".");
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-2
@@ -23,8 +23,9 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.ErrorResponseException;
|
||||
|
||||
/**
|
||||
* Subclass of {@link ErrorResponseException} that accepts a "reason" and maps
|
||||
* it to the "detail" property of {@link org.springframework.http.ProblemDetail}.
|
||||
* Subclass of {@link ErrorResponseException} that accepts a "reason", and by
|
||||
* default maps that to the {@link ErrorResponseException#setDetail(String) "detail"}
|
||||
* of the {@code ProblemDetail}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
@@ -93,6 +94,7 @@ public class ResponseStatusException extends ErrorResponseException {
|
||||
|
||||
super(status, ProblemDetail.forStatus(status), cause, messageDetailCode, messageDetailArguments);
|
||||
this.reason = reason;
|
||||
setDetail(reason);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public class UnsatisfiedRequestParameterException extends ServerWebInputExceptio
|
||||
super(initReason(conditions, params), null, null, null, new Object[] {conditions});
|
||||
this.conditions = conditions;
|
||||
this.requestParams = params;
|
||||
getBody().setDetail("Invalid request parameters.");
|
||||
setDetail("Invalid request parameters.");
|
||||
}
|
||||
|
||||
private static String initReason(List<String> conditions, MultiValueMap<String, String> queryParams) {
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ public class UnsupportedMediaTypeStatusException extends ResponseStatusException
|
||||
this.supportedMediaTypes = Collections.emptyList();
|
||||
this.bodyType = null;
|
||||
this.method = null;
|
||||
getBody().setDetail("Could not parse Content-Type.");
|
||||
setDetail("Could not parse Content-Type.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -316,7 +316,7 @@ public class ErrorResponseExceptionTests {
|
||||
ServerErrorException ex = new ServerErrorException("Failure", null);
|
||||
|
||||
assertStatus(ex, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
assertDetail(ex, null);
|
||||
assertDetail(ex, "Failure");
|
||||
assertDetailMessageCode(ex, null, new Object[] {ex.getReason()});
|
||||
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
|
||||
Reference in New Issue
Block a user