Denial of Service in Spring Framework
Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.
Affected versions
Details
Spring Framework, version 5.1, versions 5.0.x prior to 5.0.10, versions 4.3.x prior to 4.3.20, and older unsupported versions on the 4.2.x branch provide support for range requests when serving static resources through the ResourceHttpRequestHandler, or starting in 5.0 when an annotated controller returns an org.springframework.core.io.Resource. A malicious user (or attacker) can add a range header with a high number of ranges, or with wide ranges that overlap, or both, for a denial of service attack. This vulnerability affects applications that depend on either spring-webmvc or spring-webflux. Such applications must also have a registration for serving static resources (e.g. JS, CSS, images, and others), or have an annotated controller that returns an org.springframework.core.io.Resource. Spring Boot applications that depend on spring-boot-starter-web or spring-boot-starter-webflux are ready to serve static resources out of the box and are therefore vulnerable.
The fix
Release delta 5.1.0.RELEASE → 5.1.1.RELEASE (contains the fix)
src/docs/asciidoc/integration.adoc+119 −100
@@ -14,40 +14,35 @@ a number of Java EE (and related) technologies.-[[remoting]]-== Remoting and web services using Spring----[[remoting-introduction]]-=== Introduction+== Remoting and Web Services with Spring-Spring features integration classes for remoting support using various technologies. The+Spring features integration classes for remoting support with various technologies. Theremoting support eases the development of remote-enabled services, implemented by yourusual (Spring) POJOs. Currently, Spring supports the following remoting technologies:-* __Remote Method Invocation (RMI)__. Through the use of the `RmiProxyFactoryBean` and-the `RmiServiceExporter` Spring supports both traditional RMI (with `java.rmi.Remote`-interfaces and `java.rmi.RemoteException`) and transparent remoting via RMI invokers+* *Remote Method Invocation (RMI)*: Through the use of `RmiProxyFactoryBean` and+`RmiServiceExporter`, Spring supports both traditional RMI (with `java.rmi.Remote`+interfaces and `java.rmi.RemoteException`) and transparent remoting through RMI invokers(with any Java interface).-* __Spring's HTTP invoker__. Spring provides a special remoting strategy which allows-for Java serialization via HTTP, supporting any Java interface (just like the RMI-invoker). The corresponding support classes are `HttpInvokerProxyFactoryBean` and+* *Spring's HTTP invoker*: Spring provides a special remoting strategy that allows+for Java serialization though HTTP, supporting any Java interface (as the RMI+invoker does). The corresponding support classes are `HttpInvokerProxyFactoryBean` and`HttpInvokerServiceExporter`.-* __Hessian__. By using Spring's `HessianProxyFactoryBean` and the-`HessianServiceExporter` you can transparently expose your services using the+* *Hessian*: By using Spring's `HessianProxyFactoryBean` and the+`HessianServiceExporter`, you can transparently expose your services through thelightweight binary HTTP-based protocol provided by Caucho.-* __JAX-WS__. Spring provides remoting support for web services via JAX-WS (the+* *JAX-WS*: Spring provides remoting support for web services through JAX-WS (thesuccessor of JAX-RPC, as introduced in Java EE 5 and Java 6).-* __JMS__. Remoting using JMS as the underlying protocol is supported via the+* *JMS*: Remoting by using JMS as the underlying protocol is supported through the`JmsInvokerServiceExporter` and `JmsInvokerProxyFactoryBean` classes.-* __AMQP__. Remoting using AMQP as the underlying protocol is supported by the Spring+* *AMQP*: Remoting by using AMQP as the underlying protocol is supported by the SpringAMQP project.-While discussing the remoting capabilities of Spring, we'll use the following domain+While discussing the remoting capabilities of Spring, we use the following domainmodel and corresponding services:+====[source,java,indent=0][subs="verbatim,quotes"]----@@ -94,34 +89,38 @@ model and corresponding services:}----+====-We will start exposing the service to a remote client by using RMI and talk a bit about-the drawbacks of using RMI. We'll then continue to show an example using Hessian as the+This section starts by exposing the service to a remote client by using RMI and talk a bit about+the drawbacks of using RMI. It then continues with an example that uses Hessian as theprotocol.[[remoting-rmi]]-=== Exposing services using RMI+=== Exposing Services by Using RMI-Using Spring's support for RMI, you can transparently expose your services through the+By using Spring's support for RMI, you can transparently expose your services through theRMI infrastructure. After having this set up, you basically have a configuration similarto remote EJBs, except for the fact that there is no standard support for securitycontext propagation or remote transaction propagation. Spring does provide hooks for-such additional invocation context when using the RMI invoker, so you can for example-plug in security frameworks or custom security credentials here.+such additional invocation context when you use the RMI invoker, so you can, for example,+plug in security frameworks or custom security credentials.+[[remoting-rmi-server]]-==== Exporting the service using the RmiServiceExporter+==== Exporting the Service by Using `RmiServiceExporter`Using the `RmiServiceExporter`, we can expose the interface of our AccountService objectas RMI object. The interface can be accessed by using `RmiProxyFactoryBean`, or viaplain RMI in case of a traditional RMI service. The `RmiServiceExporter` explicitlysupports the exposing of any non-RMI services via RMI invokers.-Of course, we first have to set up our service in the Spring container:+We first have to set up our service in the Spring container.+The following example shows how to do so:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -129,9 +128,12 @@ Of course, we first have to set up our service in the Spring container:<!-- any additional properties, maybe a DAO? --></bean>----+====-Next we'll have to expose our service using the `RmiServiceExporter`:+Next, we have to expose our service by using `RmiServiceExporter`.+The following example shows how to do so:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -144,25 +146,26 @@ Next we'll have to expose our service using the `RmiServiceExporter`:<property name="registryPort" value="1199"/></bean>----+====-As you can see, we're overriding the port for the RMI registry. Often, your application-server also maintains an RMI registry and it is wise to not interfere with that one.-Furthermore, the service name is used to bind the service under. So right now, the-service will be bound at `'rmi://HOST:1199/AccountService'`. We'll use the URL later on+In the preceding example, we override the port for the RMI registry. Often, your application+server also maintains an RMI registry, and it is wise to not interfere with that one.+Furthermore, the service name is used to bind the service. So, in the preceding example, the+service is bound at `'rmi://HOST:1199/AccountService'`. We use this URL later onto link in the service at the client side.-[NOTE]-====-The `servicePort` property has been omitted (it defaults to 0). This means that an-anonymous port will be used to communicate with the service.-====+NOTE: The `servicePort` property has been omitted (it defaults to 0). This means that an+anonymous port is used to communicate with the service.+[[remoting-rmi-client]]-==== Linking in the service at the client+==== Linking in the Service at the Client-Our client is a simple object using the `AccountService` to manage accounts:+Our client is a simple object that uses the `AccountService` to manage accounts,+as the following example shows:+====[source,java,indent=0][subs="verbatim,quotes"]----@@ -178,10 +181,12 @@ Our client is a simple object using the `AccountService` to manage accounts:}----+====-To link in the service on the client, we'll create a separate Spring container,-containing the simple object and the service linking configuration bits:+To link in the service on the client, we create a separate Spring container,+to contain the following simple object and the service linking configuration bits:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -194,28 +199,31 @@ containing the simple object and the service linking configuration bits:<property name="serviceInterface" value="example.AccountService"/></bean>----+====-That's all we need to do to support the remote account service on the client. Spring-will transparently create an invoker and remotely enable the account service through the-`RmiServiceExporter`. At the client we're linking it in using the `RmiProxyFactoryBean`.+That is all we need to do to support the remote account service on the client. Spring+transparently creates an invoker and remotely enables the account service through the+`RmiServiceExporter`. At the client, we link it in by using the `RmiProxyFactoryBean`.[[remoting-caucho-protocols]]-=== Using Hessian to remotely call services via HTTP+=== Using Hessian to Remotely Call Services through HTTP++Hessian offers a binary HTTP-based remoting protocol. It is developed by Caucho, and you can find more+information about Hessian itself at http://www.caucho.com[].-Hessian offers a binary HTTP-based remoting protocol. It is developed by Caucho and more-information about Hessian itself can be found at http://www.caucho.com[].[[remoting-caucho-protocols-hessian]]-==== Wiring up the DispatcherServlet for Hessian and co.+==== Wiring up `DispatcherServlet` for Hessian-Hessian communicates via HTTP and does so using a custom servlet. Using Spring's-`DispatcherServlet` principles, as known from Spring Web MVC usage, you can easily wire-up such a servlet exposing your services. First we'll have to create a new servlet in-your application (this is an excerpt from `'web.xml'`):+Hessian communicates through HTTP and does so by using a custom servlet. By using Spring's+`DispatcherServlet` principles (see <<webmvc.adoc#mvc-servlet>>), we can wire+up such a servlet to expose your services. First, we have to create a new servlet in+our application, as shown in the following excerpt from `web.xml`:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -230,25 +238,28 @@ your application (this is an excerpt from `'web.xml'`):<url-pattern>/remoting/*</url-pattern></servlet-mapping>----+====-You're probably familiar with Spring's `DispatcherServlet` principles and if so, you-know that now you'll have to create a Spring container configuration resource named-`'remoting-servlet.xml'` (after the name of your servlet) in the `'WEB-INF'` directory.-The application context will be used in the next section.+If you are familiar with Spring's `DispatcherServlet` principles, you probably+know that now you have to create a Spring container configuration resource named+`remoting-servlet.xml` (after the name of your servlet) in the `WEB-INF` directory.+The application context is used in the next section.++Alternatively, consider the use of Spring's simpler `HttpRequestHandlerServlet`. Doing so+lets you embed the remote exporter definitions in your root application context (by+default, in `WEB-INF/applicationContext.xml`), with individual servlet definitions+pointing to specific exporter beans. In this case, each servlet name needs to match the bean name of+its target exporter.-Alternatively, consider the use of Spring's simpler `HttpRequestHandlerServlet`. This-allows you to embed the remote exporter definitions in your root application context (by-default in `'WEB-INF/applicationContext.xml'`), with individual servlet definitions-pointing to specific exporter beans. Each servlet name needs to match the bean name of-its target exporter in this case.[[remoting-caucho-protocols-hessian-server]]-==== Exposing your beans by using the HessianServiceExporter+==== Exposing Your Beans by Using `HessianServiceExporter`-In the newly created application context called `remoting-servlet.xml`, we'll create a-`HessianServiceExporter` exporting your services:+In the newly created application context called `remoting-servlet.xml`, we create a+`HessianServiceExporter` to export our services, as the following example shows:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -261,16 +272,18 @@ In the newly created application context called `remoting-servlet.xml`, we'll cr<property name="serviceInterface" value="example.AccountService"/></bean>----+====-Now we're ready to link in the service at the client. No explicit handler mapping is-specified, mapping request URLs onto services, so `BeanNameUrlHandlerMapping` will be-used: Hence, the service will be exported at the URL indicated through its bean name-within the containing ``DispatcherServlet``'s mapping (as defined above):-`'http://HOST:8080/remoting/AccountService'`.+Now we are ready to link in the service at the client. No explicit handler mapping is+specified (to map request URLs onto services), so we use `BeanNameUrlHandlerMapping`+used. Hence, the service is exported at the URL indicated through its bean name+within the containing `DispatcherServlet` instance's mapping (as defined earlier):+`http://HOST:8080/remoting/AccountService`.-Alternatively, create a `HessianServiceExporter` in your root application context (e.g.-in `'WEB-INF/applicationContext.xml'`):+Alternatively, you can create a `HessianServiceExporter` in your root application context (for example,+in `WEB-INF/applicationContext.xml`), as the following example shows:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -279,12 +292,14 @@ in `'WEB-INF/applicationContext.xml'`):<property name="serviceInterface" value="example.AccountService"/></bean>----+====-In the latter case, define a corresponding servlet for this exporter in `'web.xml'`,-with the same end result: The exporter getting mapped to the request path+In the latter case, you should define a corresponding servlet for this exporter in `web.xml`,+with the same end result: The exporter gets mapped to the request path at`/remoting/AccountService`. Note that the servlet name needs to match the bean name of-the target exporter.+the target exporter. The following example shows how to do so:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -298,16 +313,19 @@ the target exporter.<url-pattern>/remoting/AccountService</url-pattern></servlet-mapping>----+====+[[remoting-caucho-protocols-hessian-client]]-==== Linking in the service on the client+==== Linking in the Service on the Client-Using the `HessianProxyFactoryBean` we can link in the service at the client. The same-principles apply as with the RMI example. We'll create a separate bean factory or-application context and mention the following beans where the `SimpleObject` is using-the `AccountService` to manage accounts:+By using the `HessianProxyFactoryBean`, we can link in the service at the client. The same+principles apply as with the RMI example. We create a separate bean factory or+application context and mention the following beans where the `SimpleObject` is by using+the `AccountService` to manage accounts, as the following example shows:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -320,17 +338,20 @@ the `AccountService` to manage accounts:<property name="serviceInterface" value="example.AccountService"/></bean>----+====+[[remoting-caucho-protocols-security]]-==== Applying HTTP basic authentication to a service exposed through Hessian+==== Applying HTTP Basic Authentication to a Service Exposed through HessianOne of the advantages of Hessian is that we can easily apply HTTP basic authentication,because both protocols are HTTP-based. Your normal HTTP server security mechanism can-easily be applied through using the `web.xml` security features, for example. Usually,-you don't use per-user security credentials here, but rather shared credentials defined-at the `HessianProxyFactoryBean` level (similar to a JDBC `DataSource`).+be applied through using the `web.xml` security features, for example. Usually,+you need not use per-user security credentials here. Rather, you can use shared credentials that you define+at the `HessianProxyFactoryBean` level (similar to a JDBC `DataSource`), as the following example shows:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -343,64 +364,64 @@ at the `HessianProxyFactoryBean` level (similar to a JDBC `DataSource`).<property name="authorizedRoles" value="administrator,operator"/></bean>----+====-This is an example where we explicitly mention the `BeanNameUrlHandlerMapping` and set-an interceptor allowing only administrators and operators to call the beans mentioned in+In the preceding example, we explicitly mention the `BeanNameUrlHandlerMapping` and set+an interceptor, to let only administrators and operators call the beans mentioned inthis application context.-[NOTE]-====-Of course, this example doesn't show a flexible kind of security infrastructure. For+NOTE: The preceding example does not show a flexible kind of security infrastructure. Formore options as far as security is concerned, have a look at the Spring Security project-at http://projects.spring.io/spring-security/[].-====+at http://projects.spring.io/spring-security/.[[remoting-httpinvoker]]-=== Exposing services using HTTP invokers+=== Exposing Services by Using HTTP Invokers-As opposed to Hessian, which are both lightweight protocols using their own slim-serialization mechanisms, Spring HTTP invokers use the standard Java serialization+As opposed to Hessian, Spring HTTP invokers are both lightweight protocols that use their own slim+serialization mechanisms and use the standard Java serializationmechanism to expose services through HTTP. This has a huge advantage if your arguments-and return types are complex types that cannot be serialized using the serialization-mechanisms Hessian uses (refer to the next section for more considerations when-choosing a remoting technology).+and return types are complex types that cannot be serialized by using the serialization+mechanisms Hessian uses (see the next section for more considerations when+you choose a remoting technology).Under the hood, Spring uses either the standard facilities provided by the JDK or-Apache `HttpComponents` to perform HTTP calls. Use the latter if you need more-advanced and easier-to-use functionality. Refer to+Apache `HttpComponents` to perform HTTP calls. If you need more+advanced and easier-to-use functionality, use the latter. Seehttp://hc.apache.org/httpcomponents-client-ga/[hc.apache.org/httpcomponents-client-ga/]for more information.[WARNING]====Be aware of vulnerabilities due to unsafe Java deserialization:-Manipulated input streams could lead to unwanted code execution on the server+Manipulated input streams can lead to unwanted code execution on the server… diff truncated
src/docs/asciidoc/languages/kotlin.adoc+103 −118
@@ -1,18 +1,18 @@[[kotlin]]= Kotlin-https://kotlinlang.org[Kotlin] is a statically-typed language targeting the JVM (and other platforms)+https://kotlinlang.org[Kotlin] is a statically typed language that targets the JVM (and other platforms),which allows writing concise and elegant code while providing very goodhttps://kotlinlang.org/docs/reference/java-interop.html[interoperability] withexisting libraries written in Java.-The Spring Framework provides first-class support for Kotlin that allows developers to write-Kotlin applications almost as if the Spring Framework was a native Kotlin framework.+The Spring Framework provides first-class support for Kotlin that lets developers write+Kotlin applications almost as if the Spring Framework were a native Kotlin framework.-The easiest way to learn about Spring + Kotlin is to follow+The easiest way to learn about Spring and Kotlin is to followhttps://spring.io/guides/tutorials/spring-boot-kotlin/[this comprehensive tutorial]. Feelfree to join the #spring channel of http://slack.kotlinlang.org/[Kotlin Slack] or ask a-question with `spring` and `kotlin` tags on+question with `spring` and `kotlin` as tags onhttps://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you need support.@@ -20,178 +20,163 @@ https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you n[[kotlin-requirements]]== Requirements-Spring Framework supports Kotlin 1.1+ and requires+The Spring Framework supports Kotlin 1.1+ and requireshttps://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib[`kotlin-stdlib`]-(or one of its variants like https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jre8[`kotlin-stdlib-jre8`]+(or one of its variants, such as https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jre8[`kotlin-stdlib-jre8`]for Kotlin 1.1 or https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jdk8[`kotlin-stdlib-jdk8`] for Kotlin 1.2+)and https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-reflect[`kotlin-reflect`]-to be present on the classpath. They are provided by default if one bootstraps a Kotlin project on+to be present on the classpath. They are provided by default if you bootstrap a Kotlin project onhttps://start.spring.io/#!language=kotlin[start.spring.io].-[[kotlin-extensions]]== ExtensionsKotlin https://kotlinlang.org/docs/reference/extensions.html[extensions] provide the ability-to extend existing classes with additional functionality. The Spring Framework Kotlin APIs make-use of these extensions to add new Kotlin specific conveniences to existing Spring APIs.+to extend existing classes with additional functionality. The Spring Framework Kotlin APIs+use these extensions to add new Kotlin-specific conveniences to existing Spring APIs.-{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/[Spring Framework KDoc API] lists-and documents all the Kotlin extensions and DSLs available.+The {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/[Spring Framework KDoc API] lists+and documents all available the Kotlin extensions and DSLs.-[NOTE]-====-Keep in mind that Kotlin extensions need to be imported to be used. This means-for example that the `GenericApplicationContext.registerBean` Kotlin extension-will only be available if `import org.springframework.context.support.registerBean` is imported.+NOTE: Keep in mind that Kotlin extensions need to be imported to be used. This means,+for example, that the `GenericApplicationContext.registerBean` Kotlin extension+is available only if `org.springframework.context.support.registerBean` is imported.That said, similar to static imports, an IDE should automatically suggest the import in most cases.-====For example, https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters[Kotlin reified type parameters]provide a workaround for JVM https://docs.oracle.com/javase/tutorial/java/generics/erasure.html[generics type erasure],-and Spring Framework provides some extensions to take advantage of this feature.-This allows for a better Kotlin API `RestTemplate`, the new `WebClient` from Spring-WebFlux and for various other APIs.+and the Spring Framework provides some extensions to take advantage of this feature.+This allows for a better Kotlin API `RestTemplate`, for the new `WebClient` from Spring+WebFlux, and for various other APIs.-[NOTE]-====-Other libraries like Reactor and Spring Data also provide Kotlin extensions+NOTE: Other libraries, such as Reactor and Spring Data, also provide Kotlin extensionsfor their APIs, thus giving a better Kotlin development experience overall.-====-To retrieve a list of `Foo` objects in Java, one would normally write:+To retrieve a list of `User` objects in Java, you would normally write the following:+====[source,java,indent=0]----Flux<User> users = client.get().retrieve().bodyToFlux(User.class)----+====-Whilst with Kotlin and Spring Framework extensions, one is able to write:+With Kotlin and the Spring Framework extensions, you can instead write the following:+====[source,kotlin,indent=0]----val users = client.get().retrieve().bodyToFlux<User>()// or (both are equivalent)val users : Flux<User> = client.get().retrieve().bodyToFlux()----+====As in Java, `users` in Kotlin is strongly typed, but Kotlin's clever type inference allowsfor shorter syntax.-[[kotlin-null-safety]]== Null-safety-One of Kotlin's key features is https://kotlinlang.org/docs/reference/null-safety.html[null-safety]-- which cleanly deals with `null` values at compile time rather than bumping into the famous+One of Kotlin's key features is https://kotlinlang.org/docs/reference/null-safety.html[null-safety],+which cleanly deals with `null` values at compile time rather than bumping into the famous`NullPointerException` at runtime. This makes applications safer through nullability-declarations and expressing "value or no value" semantics without paying the cost of wrappers like `Optional`.-(Kotlin allows using functional constructs with nullable values; check out this+declarations and expressing "`value or no value`" semantics without paying the cost of wrappers, such as `Optional`.+(Kotlin allows using functional constructs with nullable values. See thishttp://www.baeldung.com/kotlin-null-safety[comprehensive guide to Kotlin null-safety].)-Although Java does not allow one to express null-safety in its type-system, Spring Framework now+Although Java does not let you express null-safety in its type-system, the Spring Frameworkprovides <<core#null-safety,null-safety of the whole Spring Framework API>>via tooling-friendly annotations declared in the `org.springframework.lang` package.By default, types from Java APIs used in Kotlin are recognized as-https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[platform types]+https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[platform types],for which null-checks are relaxed.-https://kotlinlang.org/docs/reference/java-interop.html#jsr-305-support[Kotlin support for JSR 305 annotations]-+ Spring nullability annotations provide null-safety for the whole Spring Framework API to Kotlin developers,-with the advantage of dealing with `null` related issues at compile time.+https://kotlinlang.org/docs/reference/java-interop.html#jsr-305-support[Kotlin support for JSR-305 annotations]+and Spring nullability annotations provide null-safety for the whole Spring Framework API to Kotlin developers,+with the advantage of dealing with `null`-related issues at compile time.-[NOTE]-====-Libraries like Reactor or Spring Data provide null-safe APIs leveraging this feature.-====+NOTE: Libraries such as Reactor or Spring Data provide null-safe APIs to leverage this feature.-The JSR 305 checks can be configured by adding the `-Xjsr305` compiler flag with the following+You can configure JSR-305 checks by adding the `-Xjsr305` compiler flag with the followingoptions: `-Xjsr305={strict|warn|ignore}`.-For kotlin versions 1.1+, the default behavior is the same to `-Xjsr305=warn`.-The `strict` value is required to have Spring Framework API null-safety taken in account+For kotlin versions 1.1+, the default behavior is the same as `-Xjsr305=warn`.+The `strict` value is required to have Spring Framework API null-safety taken into accountin Kotlin types inferred from Spring API but should be used with the knowledge that Spring-API nullability declaration could evolve even between minor releases and more checks may+API nullability declaration could evolve even between minor releases and that more checks maybe added in the future).-[NOTE]-====-Generic type arguments, varargs and array elements nullability are not supported yet,-but should be in an upcoming release, see https://github.com/Kotlin/KEEP/issues/79[this discussion]+NOTE: Generic type arguments, varargs, and array elements nullability are not supported yet,+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 & Interfaces+== Classes and Interfaces-Spring Framework supports various Kotlin constructs like instantiating Kotlin classes-via primary constructors, immutable classes data binding and function optional parameters+The Spring Framework supports various Kotlin constructs, such as instantiating Kotlin classes+through primary constructors, immutable classes data binding, and function optional parameterswith default values.-Kotlin parameter names are recognized via a dedicated `KotlinReflectionParameterNameDiscoverer`+Kotlin parameter names are recognized through a dedicated `KotlinReflectionParameterNameDiscoverer`,which allows finding interface method parameter names without requiring the Java 8 `-parameters`-compiler flag enabled during compilation.+compiler flag to be enabled during compilation.-https://github.com/FasterXML/jackson-module-kotlin[Jackson Kotlin module] which is required-for serializing / deserializing JSON data is automatically registered when-found in the classpath and a warning message will be logged if Jackson and Kotlin are-detected without the Jackson Kotlin module present.+The https://github.com/FasterXML/jackson-module-kotlin[Jackson Kotlin module], which is required+for serializing or deserializing JSON data, is automatically registered when+found in the classpath, and a warning message is logged if Jackson and Kotlin are+detected without the Jackson Kotlin module being present.-Configuration classes can be-https://kotlinlang.org/docs/reference/nested-classes.html[top level or nested but not inner]+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-Spring Framework also takes advantage of https://kotlinlang.org/docs/reference/null-safety.html[Kotlin null-safety]+The Spring Framework also takes advantage of https://kotlinlang.org/docs/reference/null-safety.html[Kotlin null-safety]to determine if a HTTP parameter is required without having to explicitly-define the `required` attribute. That means `@RequestParam name: String?` will be treated-as not required and conversely `@RequestParam name: String` as being required.+define the `required` attribute. That means `@RequestParam name: String?` is treated+as not required and, conversely, `@RequestParam name: String` is treated as being required.This feature is also supported on the Spring Messaging `@Header` annotation.-In a similar fashion, Spring bean injection with `@Autowired`, `@Bean` or `@Inject` uses+In a similar fashion, Spring bean injection with `@Autowired`, `@Bean`, or `@Inject` usesthis information to determine if a bean is required or not.-For example, `@Autowired lateinit var foo: Foo` implies that a bean-of type `Foo` must be registered in the application context, while `@Autowired lateinit var foo: Foo?`-won’t raise an error if such bean does not exist.+For example, `@Autowired lateinit var thing: Thing` implies that a bean+of type `Thing` must be registered in the application context, while `@Autowired lateinit var thing: Thing?`+does not raise an error if such a bean does not exist.-Following the same principle, `@Bean fun baz(foo: Foo, bar: Bar?) = Baz(foo, bar)` implies-that a bean of type `Foo` must be registered in the application context while a bean of-type `Bar` may or may not exist. The same behavior applies to autowired constructor parameters.+Following the same principle, `@Bean fun play(toy: Toy, car: Car?) = Baz(toy, Car)` implies+that a bean of type `Toy` must be registered in the application context, while a bean of+type `Car` may or may not exist. The same behavior applies to autowired constructor parameters.-[NOTE]-====-If you are using bean validation on classes with properties or a primary constructor-parameters, you may need to leverage-https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets[annotation use-site targets]-like `@field:NotNull` or `@get:Size(min=5, max=15)` as described in+NOTE: If you use bean validation on classes with properties or a primary constructor+parameters, you may need to use+https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets[annotation use-site targets],+such as `@field:NotNull` or `@get:Size(min=5, max=15)`, as described inhttps://stackoverflow.com/a/35853200/1092077[this Stack Overflow response].-====-[[kotlin-bean-definition-dsl]]-== Bean definition DSL+== Bean Definition DSL-Spring Framework 5 introduces a new way to register beans in a functional way using lambdas-as an alternative to XML or JavaConfig (`@Configuration` and `@Bean`). In a nutshell,-it makes it possible to register beans with a lambda that acts as a `FactoryBean`.-This mechanism is very efficient as it does not require any reflection or CGLIB proxies.+Spring Framework 5 introduces a new way to register beans in a functional way by using lambdas+as an alternative to XML or Java configuration (`@Configuration` and `@Bean`). In a nutshell,+it lets you register beans with a lambda that acts as a `FactoryBean`.+This mechanism is very efficient, as it does not require any reflection or CGLIB proxies.-In Java, one may for example write:+In Java, you can, for example, write the following:+====[source,java,indent=0]----GenericApplicationContext context = new GenericApplicationContext();@@ -199,10 +184,12 @@ In Java, one may for example write:context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class)));----+====-Whilst in Kotlin with reified type parameters and `GenericApplicationContext`-Kotlin extensions one can instead simply write:+In Kotlin, with reified type parameters and `GenericApplicationContext`+Kotlin extensions, you can instead write the following:+====[source,kotlin,indent=0]----val context = GenericApplicationContext().apply {@@ -210,13 +197,15 @@ Kotlin extensions one can instead simply write:registerBean { Bar(it.getBean<Foo>()) }}----+====In order to allow a more declarative approach and cleaner syntax, Spring Framework providesa {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.context.support/-bean-definition-dsl/[Kotlin bean definition DSL]-It declares an `ApplicationContextInitializer` via a clean declarative API-which enables one to deal with profiles and `Environment` for customizing-how beans are registered.+It declares an `ApplicationContextInitializer` through a clean declarative API,+which lets you deal with profiles and `Environment` for customizing+how beans are registered. The following example creates a `Play` profile:+====[source,kotlin,indent=0]----fun beans() = beans {@@ -243,17 +232,20 @@ how beans are registered.setSuffix(suffix)}}-profile("foo") {-bean<Foo>()+profile("play") {+bean<Play>()}}----+====-In this example, `bean<Routes>()` is using autowiring by constructor and `ref<Routes>()`+In the preceding example, `bean<Routes>()` uses autowiring by constructor, and `ref<Routes>()`is a shortcut for `applicationContext.getBean(Routes::class.java)`.-This `beans()` function can then be used to register beans on the application context.+You can then use this `beans()` function to register beans on the application context,+as the following example shows:+====[source,kotlin,indent=0]----val context = GenericApplicationContext().apply {@@ -261,25 +253,19 @@ This `beans()` function can then be used to register beans on the application corefresh()}------[NOTE]-====-This DSL is programmatic, thus it allows custom registration logic of beans-via an `if` expression, a `for` loop or any other Kotlin constructs.====+NOTE: This DSL is programmatic, meaning it allows custom registration logic of beans+through an `if` expression, a `for` loop, or any other Kotlin constructs.+See https://github.com/sdeleuze/spring-kotlin-functional/blob/master/src/main/kotlin/functional/Beans.kt[spring-kotlin-functional beans declaration]for a concrete example.-[NOTE]-====-Spring Boot is based on Java Config and-https://github.com/spring-projects/spring-boot/issues/8115[does not provide specific support for functional bean definition yet],-but one can experimentally use functional bean definitions via 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]+NOTE: Spring Boot is based on Java configuration 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.-====-@@ -292,9 +278,10 @@ for more details and up-to-date information.Spring Framework now comes with a{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-router-function-dsl/[Kotlin routing DSL]-that allows one to leverage the <<web-reactive#webflux-fn,WebFlux functional-API>> for writing clean and idiomatic Kotlin code:+that lets you use the <<web-reactive#webflux-fn,WebFlux functional+API>> to write clean and idiomatic Kotlin code, as the following example shows:+====[source,kotlin,indent=0]----router {@@ -314,37 +301,36 @@ API>> for writing clean and idiomatic Kotlin code:resources("/**", ClassPathResource("static/"))}------[NOTE]====-This DSL is programmatic, thus it allows custom registration logic of beans-via an `if` expression, a `for` loop or any other Kotlin constructs. That can be useful when routes need to be registered++NOTE: This DSL is programmatic, meaning that it allows custom registration logic of beans+through an `if` expression, a `for` loop, or any other Kotlin constructs. That can be useful when you need to register routesdepending on dynamic data (for example, from a database).-====See https://github.com/mixitconf/mixit/tree/bad6b92bce6193f9b3f696af9d416c276501dbf1/src/main/kotlin/mixit/web/routes[MiXiT project routes]for a concrete example.-=== Kotlin Script templates+=== Kotlin Script TemplatesAs of version 4.3, Spring Framework provides a… diff truncated
src/docs/asciidoc/languages/dynamic-languages.adoc+129 −112
@@ -1,18 +1,13 @@[[dynamic-language]]= Dynamic Language Support---[[dynamic-language-introduction]]-== Introduction--Spring 2.0 introduces comprehensive support for using classes and objects that have been-defined using a dynamic language (such as JRuby) with Spring. This support allows you to-write any number of classes in a supported dynamic language, and have the Spring-container transparently instantiate, configure and dependency inject the resulting+Spring 2.0 introduced comprehensive support for using classes and objects that have been+defined by using a dynamic language (such as JRuby) with Spring. This support lets you+write any number of classes in a supported dynamic language and have the Spring+container transparently instantiate, configure, and dependency inject the resultingobjects.-The dynamic languages currently supported are:+Spring currently supports the following dynamic languages:* JRuby 1.5+* Groovy 1.8+@@ -20,32 +15,34 @@ The dynamic languages currently supported are:.Why only these languages?****-The supported languages were chosen because __a)__ the languages have a lot of traction in-the Java enterprise community, __b)__ no requests were made for other languages at the time-that this support was added, and __c)__ the Spring developers were most familiar with-them.+We chose to support these languages because:++* The languages have a lot of traction in the Java enterprise community.+* No requests were made for other languages at the time that this support was added+* The Spring developers were most familiar with them.****-Fully working examples of where this dynamic language support can be immediately useful-are described in <<dynamic-language-scenarios>>.+You can find fully working examples of where this dynamic language support can be immediately useful+in <<dynamic-language-scenarios>>.[[dynamic-language-a-first-example]]-== A first example+== A First Example-This bulk of this chapter is concerned with describing the dynamic language support in+The bulk of this chapter is concerned with describing the dynamic language support indetail. Before diving into all of the ins and outs of the dynamic language support,-let's look at a quick example of a bean defined in a dynamic language. The dynamic-language for this first bean is Groovy (the basis of this example was taken from the-Spring test suite, so if you want to see equivalent examples in any of the other+we look at a quick example of a bean defined in a dynamic language. The dynamic+language for this first bean is Groovy. (The basis of this example was taken from the+Spring test suite. If you want to see equivalent examples in any of the othersupported languages, take a look at the source code).-Find below the `Messenger` interface that the Groovy bean is going to be implementing,-and note that this interface is defined in plain Java. Dependent objects that are-injected with a reference to the `Messenger` won't know that the underlying-implementation is a Groovy script.+The next example shows the `Messenger` interface, which the Groovy bean is going to implement.+Note that this interface is defined in plain Java. Dependent objects that are+injected with a reference to the `Messenger` do not know that the underlying+implementation is a Groovy script. The following listing shows the `Messenger` interface:+====[source,java,indent=0][subs="verbatim,quotes"]----@@ -57,9 +54,11 @@ implementation is a Groovy script.}----+====-Here is the definition of a class that has a dependency on the `Messenger` interface.+The following example defines a class that has a dependency on the `Messenger` interface:+====[source,java,indent=0][subs="verbatim,quotes"]----@@ -79,9 +78,11 @@ Here is the definition of a class that has a dependency on the `Messenger` inter}----+====-Here is an implementation of the `Messenger` interface in Groovy.+The following example implements the `Messenger` interface in Groovy:+====[source,java,indent=0][subs="verbatim,quotes"]----@@ -98,16 +99,13 @@ Here is an implementation of the `Messenger` interface in Groovy.}------Finally, here are the bean definitions that will effect the injection of the-Groovy-defined `Messenger` implementation into an instance of the-`DefaultBookingService` class.+====[NOTE]====To use the custom dynamic language tags to define dynamic-language-backed beans, youneed to have the XML Schema preamble at the top of your Spring XML configuration file.-You also need to be using a Spring `ApplicationContext` implementation as your IoC+You also need to use a Spring `ApplicationContext` implementation as your IoCcontainer. Using the dynamic-language-backed beans with a plain `BeanFactory`implementation is supported, but you have to manage the plumbing of the Spring internalsto do so.@@ -116,6 +114,11 @@ For more information on schema-based configuration, see <<appendix.adoc#xsd-confXML Schema-based configuration>>.====+Finally, the following example shows the bean definitions that effect the injection of the+Groovy-defined `Messenger` implementation into an instance of the+`DefaultBookingService` class:++====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -138,60 +141,64 @@ XML Schema-based configuration>>.</beans>----+====The `bookingService` bean (a `DefaultBookingService`) can now use its private-`messenger` member variable as normal because the `Messenger` instance that was injected-into it __is__ a `Messenger` instance. There is nothing special going on here, just+`messenger` member variable as normal, because the `Messenger` instance that was injected+into it is a `Messenger` instance. There is nothing special going on here -- justplain Java and plain Groovy.-Hopefully the above XML snippet is self-explanatory, but don't worry unduly if it isn't.-Keep reading for the in-depth detail on the whys and wherefores of the above+Hopefully, the preceding XML snippet is self-explanatory, but do not worry unduly if it is not.+Keep reading for the in-depth detail on the whys and wherefores of the precedingconfiguration.[[dynamic-language-beans]]-== Defining beans that are backed by dynamic languages+== Defining Beans that Are Backed by Dynamic Languages-This section describes exactly how you define Spring managed beans in any of the+This section describes exactly how you define Spring-managed beans in any of thesupported dynamic languages.-Please note that this chapter does not attempt to explain the syntax and idioms of the+Note that this chapter does not attempt to explain the syntax and idioms of thesupported dynamic languages. For example, if you want to use Groovy to write certain of-the classes in your application, then the assumption is that you already know Groovy. If-you need further details about the dynamic languages themselves, please-consult <<dynamic-language-resources>> at the end of this chapter.+the classes in your application, we assume that you already know Groovy. If+you need further details about the dynamic languages themselves, see+<<dynamic-language-resources>> at the end of this chapter.+[[dynamic-language-beans-concepts]]-=== Common concepts+=== Common ConceptsThe steps involved in using dynamic-language-backed beans are as follows:-* Write the test for the dynamic language source code (naturally)-* __Then__ write the dynamic language source code itself :)-* Define your dynamic-language-backed beans using the appropriate `<lang:language/>`-element in the XML configuration (you can of course define such beans programmatically-using the Spring API - although you will have to consult the source code for-directions on how to do this as this type of advanced configuration is not covered in-this chapter). Note this is an iterative step. You will need at least one bean-definition per dynamic language source file (although the same dynamic language source-file can of course be referenced by multiple bean definitions).+. Write the test for the dynamic language source code (naturally).+. Then write the dynamic language source code itself.+. Define your dynamic-language-backed beans by using the appropriate `<lang:language/>`+element in the XML configuration (you can define such beans programmatically by+using the Spring API, although you will have to consult the source code for+directions on how to do this, as this chapter does not cover this type of advanced configuration).+Note that this is an iterative step. You need at least one bean+definition for each dynamic language source file (although multiple bean definitions can reference the same dynamic language source+file).The first two steps (testing and writing your dynamic language source files) are beyond-the scope of this chapter. Refer to the language specification and / or reference manual+the scope of this chapter. See the language specification and reference manualfor your chosen dynamic language and crack on with developing your dynamic language-source files. You __will__ first want to read the rest of this chapter though, as+source files. You first want to read the rest of this chapter, though, asSpring's dynamic language support does make some (small) assumptions about the contentsof your dynamic language source files.++[[dynamic-language-beans-concepts-xml-language-element]]==== The <lang:language/> element-The final step involves defining dynamic-language-backed bean definitions, one for each+The final step in the list in the <<dynamic-language-beans-concepts,preceding section>> involves defining dynamic-language-backed bean definitions, one for eachbean that you want to configure (this is no different from normal JavaBeanconfiguration). However, instead of specifying the fully qualified classname of the-class that is to be instantiated and configured by the container, you use the+class that is to be instantiated and configured by the container, you can use the`<lang:language/>` element to define the dynamic language-backed bean.Each of the supported languages has a corresponding `<lang:language/>` element:@@ -202,42 +209,42 @@ Each of the supported languages has a corresponding `<lang:language/>` element:The exact attributes and child elements that are available for configuration depends onexactly which language the bean has been defined in (the language-specific sections-below provide the full lowdown on this).+later in this chapter detail this).++[[dynamic-language-refreshable-beans]]-==== Refreshable beans+==== Refreshable Beans-One of the (if not __the__) most compelling value adds of the dynamic language support-in Spring is the__'refreshable bean'__ feature.+One of the (and perhaps the single) most compelling value adds of the dynamic language support+in Spring is the "`refreshable bean`" feature.-A refreshable bean is a dynamic-language-backed bean that with a small amount of+A refreshable bean is a dynamic-language-backed bean. With a small amount ofconfiguration, a dynamic-language-backed bean can monitor changes in its underlying-source file resource, and then reload itself when the dynamic language source file is-changed (for example when a developer edits and saves changes to the file on the-filesystem).+source file resource and then reload itself when the dynamic language source file is+changed (for example, when you edit and save changes to the file on the+file system).-This allows a developer to deploy any number of dynamic language source files as part of+This lets you deploy any number of dynamic language source files as part ofan application, configure the Spring container to create beans backed by dynamic-language source files (using the mechanisms described in this chapter), and then later,-as requirements change or some other external factor comes into play, simply edit a-dynamic language source file and have any change they make reflected in the bean that is+language source files (using the mechanisms described in this chapter), and (later,+as requirements change or some other external factor comes into play) edit a+dynamic language source file and have any change they make be reflected in the bean that isbacked by the changed dynamic language source file. There is no need to shut down arunning application (or redeploy in the case of a web application). The-dynamic-language-backed bean so amended will pick up the new state and logic from the+dynamic-language-backed bean so amended picks up the new state and logic from thechanged dynamic language source file.-[NOTE]-====-Please note that this feature is __off__ by default.-====+NOTE: This feature is off by default.-Let's take a look at an example to see just how easy it is to start using refreshable-beans. To __turn on__ the refreshable beans feature, you simply have to specify exactly-__one__ additional attribute on the `<lang:language/>` element of your bean definition.-So if we stick with <<dynamic-language-a-first-example,the example>> from earlier in this-chapter, here's what we would change in the Spring XML configuration to effect+Now we can take a look at an example to see how easy it is to start using refreshable+beans. To turn on the refreshable beans feature, you have to specify exactly+one additional attribute on the `<lang:language/>` element of your bean definition.+So, if we stick with <<dynamic-language-a-first-example,the example>> from earlier in this+chapter, the following example shows what we would change in the Spring XML configuration to effectrefreshable beans:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -256,21 +263,25 @@ refreshable beans:</beans>----+====-That really is all you have to do. The `'refresh-check-delay'` attribute defined on the-`'messenger'` bean definition is the number of milliseconds after which the bean will be+That really is all you have to do. The `refresh-check-delay` attribute defined on the+`messenger` bean definition is the number of milliseconds after which the bean isrefreshed with any changes made to the underlying dynamic language source file. You canturn off the refresh behavior by assigning a negative value to the-`'refresh-check-delay'` attribute. Remember that, by default, the refresh behavior is-disabled. If you don't want the refresh behavior, then simply don't define the attribute.--If we then run the following application we can exercise the refreshable feature; please-do excuse the __'jumping-through-hoops-to-pause-the-execution'__ shenanigans in this-next slice of code. The `System.in.read()` call is only there so that the execution of-the program pauses while I (the author) go off and edit the underlying dynamic language-source file so that the refresh will trigger on the dynamic-language-backed bean when+`refresh-check-delay` attribute. Remember that, by default, the refresh behavior is+disabled. If you do not want the refresh behavior, do not define the attribute.++If we then run the following application, we can exercise the refreshable feature (Please+do excuse the "`jumping-through-hoops-to-pause-the-execution`" shenanigans in this+next slice of code.) The `System.in.read()` call is only there so that the execution of+the program pauses while you (the developer in this scenario) go off and edit the underlying dynamic language+source file so that the refresh triggers on the dynamic-language-backed bean whenthe program resumes execution.+The following listing shows this sample application:++====[source,java,indent=0][subs="verbatim,quotes"]----@@ -290,12 +301,14 @@ the program resumes execution.}}----+====-Let's assume then, for the purposes of this example, that all calls to the+Assume then, for the purposes of this example, that all calls to the`getMessage()` method of `Messenger` implementations have to be changed such that the-message is surrounded by quotes. Below are the changes that I (the author) make to the-`Messenger.groovy` source file when the execution of the program is paused.+message is surrounded by quotation marks. The following listing shows the changes that you (the developer) should make to the+`Messenger.groovy` source file when the execution of the program is paused:+====[source,java,indent=0][subs="verbatim,quotes"]----@@ -315,38 +328,42 @@ message is surrounded by quotes. Below are the changes that I (the author) make}}----+====-When the program executes, the output before the input pause will be __I Can Do The-Frug__. After the change to the source file is made and saved, and the program resumes+When the program runs, the output before the input pause will be `I Can Do The+Frug`. After the change to the source file is made and saved and the program resumesexecution, the result of calling the `getMessage()` method on the-dynamic-language-backed `Messenger` implementation will be __'I Can Do The Frug'__-(notice the inclusion of the additional quotes).+dynamic-language-backed `Messenger` implementation is `'I Can Do The Frug'`+(notice the inclusion of the additional quotation marks).-It is important to understand that changes to a script will __not__ trigger a refresh if-the changes occur within the window of the `'refresh-check-delay'` value. It is equally-important to understand that changes to the script are __not__ actually 'picked up' until+Changes to a script do not trigger a refresh if+the changes occur within the window of the `refresh-check-delay` value.+Changes to the script are not actually picked up untila method is called on the dynamic-language-backed bean. It is only when a method iscalled on a dynamic-language-backed bean that it checks to see if its underlying script-source has changed. Any exceptions relating to refreshing the script (such as-encountering a compilation error, or finding that the script file has been deleted) will-result in a __fatal__ exception being propagated to the calling code.--The refreshable bean behavior described above does __not__ apply to dynamic language-source files defined using the `<lang:inline-script/>` element notation (see-<<dynamic-language-beans-inline>>). Additionally, it __only__ applies to beans where-changes to the underlying source file can actually be detected; for example, by code+source has changed. Any exceptions that relate to refreshing the script (such as+encountering a compilation error or finding that the script file has been deleted)+results in a fatal exception being propagated to the calling code.++The refreshable bean behavior described earlier does not apply to dynamic language+source files defined with the `<lang:inline-script/>` element notation (see+<<dynamic-language-beans-inline>>). Additionally, it applies only to beans where+changes to the underlying source file can actually be detected (for example, by codethat checks the last modified date of a dynamic language source file that exists on the-filesystem.+file system).++[[dynamic-language-beans-inline]]-==== Inline dynamic language source files+==== Inline Dynamic Language Source Files-The dynamic language support can also cater for dynamic language source files that are+The dynamic language support can also cater to dynamic language source files that areembedded directly in Spring bean definitions. More specifically, the-`<lang:inline-script/>` element allows you to define dynamic language source immediately-inside a Spring configuration file. An example will perhaps make the inline script-feature crystal clear:+`<lang:inline-script/>` element lets you define dynamic language source immediately+inside a Spring configuration file. An example might clarify how the inline script+feature works:+====… diff truncated
spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/DispatcherHandlerIntegrationTests.java+96 −0
@@ -0,0 +1,96 @@+/*+* Copyright 2002-2018 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.+* You may obtain a copy of the License at+*+* http://www.apache.org/licenses/LICENSE-2.0+*+* Unless required by applicable law or agreed to in writing, software+* distributed under the License is distributed on an "AS IS" BASIS,+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+* See the License for the specific language governing permissions and+* limitations under the License.+*/++package org.springframework.web.reactive.function.server.support;++import org.junit.Test;+import reactor.core.publisher.Mono;++import org.springframework.context.annotation.AnnotationConfigApplicationContext;+import org.springframework.context.annotation.Bean;+import org.springframework.context.annotation.Configuration;+import org.springframework.http.MediaType;+import org.springframework.http.ResponseEntity;+import org.springframework.http.server.reactive.AbstractHttpHandlerIntegrationTests;+import org.springframework.http.server.reactive.HttpHandler;+import org.springframework.web.client.RestTemplate;+import org.springframework.web.reactive.DispatcherHandler;+import org.springframework.web.reactive.config.EnableWebFlux;+import org.springframework.web.reactive.function.server.RouterFunction;+import org.springframework.web.reactive.function.server.ServerRequest;+import org.springframework.web.reactive.function.server.ServerResponse;+import org.springframework.web.server.adapter.WebHttpHandlerBuilder;++import static org.junit.Assert.*;+import static org.springframework.web.reactive.function.server.RequestPredicates.accept;+import static org.springframework.web.reactive.function.server.RouterFunctions.route;++/**+* @author Arjen Poutsma+*/+public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTests {++private final RestTemplate restTemplate = new RestTemplate();++@Override+protected HttpHandler createHttpHandler() {+AnnotationConfigApplicationContext wac = new AnnotationConfigApplicationContext();+wac.register(TestConfiguration.class);+wac.refresh();++return WebHttpHandlerBuilder.webHandler(new DispatcherHandler(wac)).build();+}++@Test+public void nested() {+ResponseEntity<String> result = this.restTemplate+.getForEntity("http://localhost:" + this.port + "/foo/bar", String.class);++assertEquals(200, result.getStatusCodeValue());+}+++@Configuration+@EnableWebFlux+static class TestConfiguration {++@Bean+public RouterFunction<ServerResponse> router(Handler handler) {+return route()+.path("/foo", () -> route()+.nest(accept(MediaType.APPLICATION_JSON), builder -> builder+.GET("/bar", handler::handle))+.build())+.build();+}++@Bean+public Handler handler() {+return new Handler();+}+}++static class Handler {++public Mono<ServerResponse> handle(ServerRequest request) {+return ServerResponse.ok().build();+}+}+++++}.../beans/factory/NoUniqueBeanDefinitionException.java | 4 ++--.../annotation/AutowiredAnnotationBeanPostProcessor.java | 2 +-.../beans/factory/config/BeanExpressionContext.java | 4 ++--.../factory/config/PreferencesPlaceholderConfigurer.java | 4 ++--.../beans/factory/config/PropertyOverrideConfigurer.java | 2 +-.../factory/support/AbstractAutowireCapableBeanFactory.java | 4 ++--.../beans/factory/support/DefaultListableBeanFactory.java | 2 +-.../factory/support/PropertiesBeanDefinitionReader.java | 2 +-.../beans/factory/support/SimpleInstantiationStrategy.java | 2 +-.../beans/factory/support/StaticListableBeanFactory.java | 2 +-.../factory/xml/SimpleConstructorNamespaceHandler.java | 6 +++---.../java/org/springframework/core/AttributeAccessor.java | 4 ++--.../src/main/java/org/springframework/util/ObjectUtils.java | 4 ++--.../util/UpdateMessageDigestInputStream.java | 6 +++---14 files changed, 24 insertions(+), 24 deletions(-)
src/docs/asciidoc/data-access.adoc+26 −20
@@ -1556,7 +1556,7 @@ applies to transactions). See <<core.adoc#aop,AOP>> for detailed coverage of theconfiguration and AOP in general.The following code shows the simple profiling aspect discussed earlier:-.+[source,java,indent=0][subs="verbatim,quotes"]----@@ -3221,16 +3221,14 @@ connection are made.To configure a `DriverManagerDataSource`:. Obtain a connection with `DriverManagerDataSource` as you typically obtain a JDBC-connection.-. Specify the fully qualified classname of the JDBC driver so that the-`DriverManager` can load the driver class.-. Provide a URL that varies between JDBC-drivers. (See the documentation for your driver for the correct value.)-. Provide-a username and a password to connect to the database.+connection.+. Specify the fully qualified classname of the JDBC driver so that the `DriverManager`+can load the driver class.+. Provide a URL that varies between JDBC drivers. (See the documentation for your driver+for the correct value.)+. Provide a username and a password to connect to the database.-The following example shows how to-configure a `DriverManagerDataSource` in Java:+The following example shows how to configure a `DriverManagerDataSource` in Java:====[source,java,indent=0]@@ -3246,6 +3244,7 @@ configure a `DriverManagerDataSource` in Java:The following example shows the corresponding XML configuration:+====[source,java,indent=0][subs="verbatim,quotes"]----@@ -3258,6 +3257,7 @@ The following example shows the corresponding XML configuration:<context:property-placeholder location="jdbc.properties"/>----+====The next two examples show the basic connectivity and configuration for DBCP and C3P0.To learn about more options that help control the pooling features, see the product@@ -3506,14 +3506,15 @@ The following example shows a batch update using named parameters:----====-For an SQL statement that uses the classic `?` placeholders, you pass in a list containing an-object array with the update values. This object array must have one entry for each-placeholder in the SQL statement, and they must be in the same order as they are defined-in the SQL statement.+For an SQL statement that uses the classic `?` placeholders, you pass in a list+containing an object array with the update values. This object array must have one entry+for each placeholder in the SQL statement, and they must be in the same order as they are+defined in the SQL statement.-The following example is the same as the preceding example, except that it uses classic JDBC "?" placeholders:+The following example is the same as the preceding example, except that it uses classic+JDBC `?` placeholders:-===+====[source,java,indent=0][subs="verbatim,quotes"]----@@ -3542,9 +3543,9 @@ The following example is the same as the preceding example, except that it uses----====-All of the batch update methods that we described earlier return an `int` array containing the number of-affected rows for each batch entry. This count is reported by the JDBC driver. If the-count is not available, the JDBC driver returns a value of `-2`.+All of the batch update methods that we described earlier return an `int` array+containing the number of affected rows for each batch entry. This count is reported by+the JDBC driver. If the count is not available, the JDBC driver returns a value of `-2`.[NOTE]====@@ -4271,6 +4272,7 @@ thread-safe after it is compiled, so, as long as these instances are created wheis initialized, they can be kept as instance variables and be reused. The followingexample shows how to define such a class:+====[source,java,indent=0][subs="verbatim,quotes"]----@@ -4285,6 +4287,7 @@ example shows how to define such a class:return actorMappingQuery.findObject(id);}----+====The method in the preceding example retrieves the customer with the `id` that is passed in as theonly parameter. Since we want only one object to be returned, we call the `findObject` convenience@@ -6802,7 +6805,10 @@ preamble of the XML configuration file. The following example shows how to do so<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"-xmlns:oxm="http://www.springframework.org/schema/oxm" xsi:schemaLocation="http://www.springframework.org/schema/beans <1> http://www.springframework.org/schema/beans/spring-beans.xsd **http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd"**>+xmlns:oxm="http://www.springframework.org/schema/oxm"+xsi:schemaLocation="+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd+http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd"> <1>----<1> Reference the `oxm` schema.====src/docs/asciidoc/data-access-appendix.adoc | 28 ++++++++++-----------src/docs/asciidoc/data-access.adoc | 6 ++---src/docs/asciidoc/web/webflux.adoc | 4 +--3 files changed, 19 insertions(+), 19 deletions(-)
src/docs/asciidoc/data-access-appendix.adoc+14 −8
@@ -37,16 +37,19 @@ are available to you:----<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"-xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"-xmlns:aop="http://www.springframework.org/schema/aop"-xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" <1>+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"+xmlns:aop="http://www.springframework.org/schema/aop"+xmlns:tx="http://www.springframework.org/schema/tx" <1>+xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd <2>-http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->+http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">++<!-- bean definitions here --></beans>-----<1> Specify the namespace.+<1> Declare usage of the `tx` namespace.<2> Specify the location (with other schema locations).====@@ -77,12 +80,15 @@ the correct schema so that the elements in the `jdbc` namespace are available to<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"-xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation=" <2>+xmlns:jdbc="http://www.springframework.org/schema/jdbc" <1>+xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd-http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"> <!-- bean definitions here --> <2>+http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"> <2>++<!-- bean definitions here --></beans>-----<1> Specify the namespace.+<1> Declare usage of the `jdbc` namespace.<2> Specify the location (with other schema locations).====
src/docs/asciidoc/integration-appendix.adoc+108 −56
@@ -1,8 +1,6 @@= Appendix--[[xsd-schemas]]== XML Schemas@@ -11,15 +9,16 @@ This part of the appendix lists XML schemas related to integration technologies.[[xsd-schemas-jee]]-=== The jee schema+=== The `jee` Schema-The `jee` tags deal with Java EE (Java Enterprise Edition)-related configuration issues,+The `jee` elements deal with issues related to Java EE (Java Enterprise Edition) configuration,such as looking up a JNDI object and defining EJB references.-To use the tags in the `jee` schema, you need to have the following preamble at the top-of your Spring XML configuration file; the text in the following snippet references the-correct schema so that the tags in the `jee` namespace are available to you.+To use the elements in the `jee` schema, you need to have the following preamble at the top+of your Spring XML configuration file. The text in the following snippet references the+correct schema so that the elements in the `jee` namespace are available to you:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -28,17 +27,22 @@ correct schema so that the tags in the `jee` namespace are available to you.xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"__xmlns:jee="http://www.springframework.org/schema/jee"__ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd-__http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"__> <!-- bean definitions here -->+__http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"__>+<!-- bean definitions here --></beans>----+====+[[xsd-schemas-jee-jndi-lookup]]==== <jee:jndi-lookup/> (simple)-Before...+The following example shows how to use JNDI to look up a data source without the `jee`+schema:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -50,9 +54,12 @@ Before...<property name="dataSource" ref="**dataSource**"/></bean>----+====-After...+The following example shows how to use JNDI to look up a data source with the `jee`+schema:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -63,13 +70,17 @@ After...<property name="dataSource" ref="**dataSource**"/></bean>----+====+[[xsd-schemas-jee-jndi-lookup-environment-single]]-==== <jee:jndi-lookup/> (with single JNDI environment setting)+==== `<jee:jndi-lookup/>` (with Single JNDI Environment Setting)-Before...+The following example shows how to use JNDI to look up an environment variable without+`jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -77,28 +88,31 @@ Before...<property name="jndiName" value="jdbc/MyDataSource"/><property name="jndiEnvironment"><props>-<prop key="foo">bar</prop>+<prop key="ping">pong</prop></props></property></bean>----+====-After...+The following example shows how to use JNDI to look up an environment variable with `jee`:[source,xml,indent=0][subs="verbatim,quotes"]----<jee:jndi-lookup id="simple" jndi-name="jdbc/MyDataSource">-<jee:environment>foo=bar</jee:environment>+<jee:environment>ping=pong</jee:environment></jee:jndi-lookup>----[[xsd-schemas-jee-jndi-lookup-evironment-multiple]]-==== <jee:jndi-lookup/> (with multiple JNDI environment settings)+==== `<jee:jndi-lookup/>` (with Multiple JNDI Environment Settings)-Before...+The following example shows how to use JNDI to look up multiple environment variables+without `jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -106,33 +120,39 @@ Before...<property name="jndiName" value="jdbc/MyDataSource"/><property name="jndiEnvironment"><props>-<prop key="foo">bar</prop>+<prop key="sing">song</prop><prop key="ping">pong</prop></props></property></bean>----+====-After...+The following example shows how to use JNDI to look up multiple environment variables with+`jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----<jee:jndi-lookup id="simple" jndi-name="jdbc/MyDataSource"><!-- newline-separated, key-value pairs for the environment (standard Properties format) --><jee:environment>-foo=bar+sing=songping=pong</jee:environment></jee:jndi-lookup>----+====[[xsd-schemas-jee-jndi-lookup-complex]]-==== <jee:jndi-lookup/> (complex)+==== `<jee:jndi-lookup/>` (Complex)-Before...+The following example shows how to use JNDI to look up a data source and a number of+different properties without `jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -141,13 +161,16 @@ Before...<property name="cache" value="true"/><property name="resourceRef" value="true"/><property name="lookupOnStartup" value="false"/>-<property name="expectedType" value="com.myapp.DefaultFoo"/>-<property name="proxyInterface" value="com.myapp.Foo"/>+<property name="expectedType" value="com.myapp.DefaultThing"/>+<property name="proxyInterface" value="com.myapp.Thing"/></bean>----+====-After...+The following example shows how to use JNDI to look up a data source and a number of+different properties with `jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -156,18 +179,22 @@ After...cache="true"resource-ref="true"lookup-on-startup="false"-expected-type="com.myapp.DefaultFoo"-proxy-interface="com.myapp.Foo"/>+expected-type="com.myapp.DefaultThing"+proxy-interface="com.myapp.Thing"/>----+====+[[xsd-schemas-jee-local-slsb]]-==== <jee:local-slsb/> (simple)+==== `<jee:local-slsb/>` (Simple)-The `<jee:local-slsb/>` tag configures a reference to an EJB Stateless SessionBean.+The `<jee:local-slsb/>` element configures a reference to a local EJB Stateless SessionBean.-Before...+The following example shows how to configures a reference to a local EJB Stateless+SessionBean without `jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -177,35 +204,49 @@ Before...<property name="businessInterface" value="com.foo.service.RentalService"/></bean>----+====-After...+The following example shows how to configures a reference to a local EJB Stateless+SessionBean with `jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----<jee:local-slsb id="simpleSlsb" jndi-name="ejb/RentalServiceBean"business-interface="com.foo.service.RentalService"/>----+====+[[xsd-schemas-jee-local-slsb-complex]]-==== <jee:local-slsb/> (complex)+==== `<jee:local-slsb/>` (Complex)++The `<jee:local-slsb/>` element configures a reference to a local EJB Stateless SessionBean.++The following example shows how to configures a reference to a local EJB Stateless+SessionBean and a number of properties without `jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----<bean id="complexLocalEjb"class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean"><property name="jndiName" value="ejb/RentalServiceBean"/>-<property name="businessInterface" value="com.foo.service.RentalService"/>+<property name="businessInterface" value="com.example.service.RentalService"/><property name="cacheHome" value="true"/><property name="lookupHomeOnStartup" value="true"/><property name="resourceRef" value="true"/></bean>----+====-After...+The following example shows how to configures a reference to a local EJB Stateless+SessionBean and a number of properties with `jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -216,16 +257,19 @@ After...lookup-home-on-startup="true"resource-ref="true">----+====[[xsd-schemas-jee-remote-slsb]]==== <jee:remote-slsb/>-The `<jee:remote-slsb/>` tag configures a reference to a `remote` EJB Stateless+The `<jee:remote-slsb/>` element configures a reference to a `remote` EJB StatelessSessionBean.-Before...+The following example shows how to configures a reference to a remote EJB Stateless+SessionBean without `jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -240,9 +284,12 @@ Before...<property name="refreshHomeOnConnectFailure" value="true"/></bean>----+====-After...+The following example shows how to configures a reference to a remote EJB Stateless+SessionBean with `jee`:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -255,24 +302,25 @@ After...home-interface="com.foo.service.RentalService"refresh-home-on-connect-failure="true">-----+====[[xsd-schemas-jms]]-=== The jms schema+=== The `jms` Schema-The `jms` tags deal with configuring JMS-related beans such as Spring's-<<integration.adoc#jms-mdp,MessageListenerContainers>>. These tags are detailed in the+The `jms` elements deal with configuring JMS-related beans, such as Spring's+<<integration.adoc#jms-mdp,Message Listener Containers>>. These elements are detailed in thesection of the <<integration.adoc#jms,JMS chapter>> entitled <<integration.adoc#jms-namespace,-JMS namespace support>>. Please do consult that chapter for full details on this support-and the `jms` tags themselves.+JMS Namespace Support>>. See that chapter for full details on this support+and the `jms` elements themselves.-In the interest of completeness, to use the tags in the `jms` schema, you need to have-the following preamble at the top of your Spring XML configuration file; the text in the-following snippet references the correct schema so that the tags in the `jms` namespace-are available to you.+In the interest of completeness, to use the elements in the `jms` schema, you need to have+the following preamble at the top of your Spring XML configuration file. The text in the+following snippet references the correct schema so that the elements in the `jms` namespace+are available to you:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -285,28 +333,31 @@ are available to you.</beans>----+====+[[xsd-schemas-context-mbe]]-=== <context:mbean-export/>+=== Using `<context:mbean-export/>`This element is detailed in-<<integration.adoc#jmx-context-mbeanexport, Configuring annotation based MBean export>>.+<<integration.adoc#jmx-context-mbeanexport, Configuring Annotation-based MBean Export>>.[[xsd-schemas-cache]]-=== The cache schema+=== The `cache` Schema-The `cache` tags can be used to enable support for Spring's `@CacheEvict`, `@CachePut`+You can use the `cache` elements to enable support for Spring's `@CacheEvict`, `@CachePut`,and `@Caching` annotations. It it also supports declarative XML-based caching. See-<<integration.adoc#cache-annotation-enable,Enable caching annotations>> and-<<integration.adoc#cache-declarative-xml,Declarative XML-based caching>> for details.+<<integration.adoc#cache-annotation-enable,Enabling Caching Annotations>> and+<<integration.adoc#cache-declarative-xml,Declarative XML-based Caching>> for details.-To use the tags in the `cache` schema, you need to have the following preamble at the-top of your Spring XML configuration file; the text in the following snippet references-the correct schema so that the tags in the `cache` namespace are available to you.+To use the elements in the `cache` schema, you need to have the following preamble at the+top of your Spring XML configuration file. The text in the following snippet references+the correct schema so that the elements in the `cache` namespace are available to you:+====[source,xml,indent=0][subs="verbatim,quotes"]----@@ -319,3 +370,4 @@ the correct schema so that the tags in the `cache` namespace are available to yo</beans>----+====
src/docs/asciidoc/data-access.adoc+5 −4
@@ -6805,12 +6805,13 @@ preamble of the XML configuration file. The following example shows how to do so<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"-xmlns:oxm="http://www.springframework.org/schema/oxm"-xsi:schemaLocation="-http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd-http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd"> <1>+xmlns:oxm="http://www.springframework.org/schema/oxm" <1>+xsi:schemaLocation="http://www.springframework.org/schema/beans+http://www.springframework.org/schema/beans/spring-beans.xsd+http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd"> <2>----<1> Reference the `oxm` schema.+<2> Specify the `oxm` schema location.====Currently, the schema makes the following elements available:
spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java+20 −22
@@ -74,15 +74,15 @@* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,* if available, as a direct alternative to Spring's own {@code @Autowired}.*-* <p>Only one constructor (at max) of any given bean class may carry this-* annotation with the 'required' parameter set to {@code true},-* indicating <i>the</i> constructor to autowire when used as a Spring bean.-* If multiple <i>non-required</i> constructors carry the annotation, they-* will be considered as candidates for autowiring. The constructor with-* the greatest number of dependencies that can be satisfied by matching-* beans in the Spring container will be chosen. If none of the candidates-* can be satisfied, then a default constructor (if present) will be used.-* An annotated constructor does not have to be public.+* <p>Only one constructor (at max) of any given bean class may declare this annotation+* with the 'required' parameter set to {@code true}, indicating <i>the</i> constructor+* to autowire when used as a Spring bean. If multiple <i>non-required</i> constructors+* declare the annotation, they will be considered as candidates for autowiring.+* The constructor with the greatest number of dependencies that can be satisfied by+* matching beans in the Spring container will be chosen. If none of the candidates+* can be satisfied, then a primary/default constructor (if present) will be used.+* If a class only declares a single constructor to begin with, it will always be used,+* even if not annotated. An annotated constructor does not have to be public.** <p>Fields are injected right after construction of a bean, before any* config methods are invoked. Such a config field does not have to be public.@@ -161,11 +161,11 @@ public AutowiredAnnotationBeanPostProcessor() {/*** Set the 'autowired' annotation type, to be used on constructors, fields,* setter methods and arbitrary config methods.-* <p>The default autowired annotation type is the Spring-provided-* {@link Autowired} annotation, as well as {@link Value}.+* <p>The default autowired annotation type is the Spring-provided {@link Autowired}+* annotation, as well as {@link Value}.* <p>This setter property exists so that developers can provide their own-* (non-Spring-specific) annotation type to indicate that a member is-* supposed to be autowired.+* (non-Spring-specific) annotation type to indicate that a member is supposed+* to be autowired.*/public void setAutowiredAnnotationType(Class<? extends Annotation> autowiredAnnotationType) {Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null");@@ -176,11 +176,11 @@ public void setAutowiredAnnotationType(Class<? extends Annotation> autowiredAnno/*** Set the 'autowired' annotation types, to be used on constructors, fields,* setter methods and arbitrary config methods.-* <p>The default autowired annotation type is the Spring-provided-* {@link Autowired} annotation, as well as {@link Value}.+* <p>The default autowired annotation type is the Spring-provided {@link Autowired}+* annotation, as well as {@link Value}.* <p>This setter property exists so that developers can provide their own-* (non-Spring-specific) annotation types to indicate that a member is-* supposed to be autowired.+* (non-Spring-specific) annotation types to indicate that a member is supposed+* to be autowired.*/public void setAutowiredAnnotationTypes(Set<Class<? extends Annotation>> autowiredAnnotationTypes) {Assert.notEmpty(autowiredAnnotationTypes, "'autowiredAnnotationTypes' must not be empty");@@ -189,8 +189,7 @@ public void setAutowiredAnnotationTypes(Set<Class<? extends Annotation>> autowir}/**-* Set the name of a parameter of the annotation that specifies-* whether it is required.+* Set the name of a parameter of the annotation that specifies whether it is required.* @see #setRequiredParameterValue(boolean)*/public void setRequiredParameterName(String requiredParameterName) {@@ -199,9 +198,8 @@ public void setRequiredParameterName(String requiredParameterName) {/*** Set the boolean value that marks a dependency as required-* <p>For example if using 'required=true' (the default),-* this value should be {@code true}; but if using-* 'optional=false', this value should be {@code false}.+* <p>For example if using 'required=true' (the default), this value should be+* {@code true}; but if using 'optional=false', this value should be {@code false}.* @see #setRequiredParameterName(String)*/public void setRequiredParameterValue(boolean requiredParameterValue) {methods.../commons/logging/LogFactoryService.java | 30 ++++++++++++++++++-1 file changed, 29 insertions(+), 1 deletion(-)
src/docs/asciidoc/testing.adoc+10 −10
@@ -1264,7 +1264,7 @@ programming model in JUnit 5):* <<integration-testing-annotations-junit-jupiter-springjunitconfig>>* <<integration-testing-annotations-junit-jupiter-springjunitwebconfig>>* <<integration-testing-annotations-junit-jupiter-enabledif>>-* <<integration-testing-annotations-junit-jupiter=-disabledif>>+* <<integration-testing-annotations-junit-jupiter-disabledif>>@@ -1406,7 +1406,7 @@ example, you can create a custom `@EnabledOnMac` annotation as follows:-[[integration-testing-annotations-junit-jupiter=-disabledif]]+[[integration-testing-annotations-junit-jupiter-disabledif]]===== `@DisabledIf``@DisabledIf` is used to signal that the annotated JUnit Jupiter test class or test@@ -1627,8 +1627,9 @@ configuration of individual JUnit Jupiter based test methods, as follows:----====-For further details, see the <<core.adoc#annotation-programming-model,Spring-Annotation Programming Model>>.+For further details, see the+https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model[Spring Annotation Programming Model]+wiki page.@@ -1670,9 +1671,8 @@ in turn, manages a `TestContext` that holds the context of the current test. Theand delegates to `TestExecutionListener` implementations, which instrument the actualtest execution by providing dependency injection, managing transactions, and so on. A`SmartContextLoader` is responsible for loading an `ApplicationContext` for a given test-class. See the {api-spring-framework}[Javadoc] and the Spring test suite for further-information and examples of various implementations.-+class. See the {api-spring-framework}/test/context/package-summary.html[Javadoc] and the+Spring test suite for further information and examples of various implementations.===== `TestContext`@@ -3860,7 +3860,7 @@ of `PlatformTransactionManager` within the test's `ApplicationContext`, you canqualifier by using `@Transactional("myTxMgr")` or `@Transactional(transactionManager ="myTxMgr")`, or `TransactionManagementConfigurer` can be implemented by an`@Configuration` class. Consult the-{api-spring-framework}/test/context/transaction/TestContextTransactionUtils.html#retrieveTransactionManager[Javadoc+{api-spring-framework}/test/context/transaction/TestContextTransactionUtils.html#retrieveTransactionManager-org.springframework.test.context.TestContext-java.lang.String-[Javadocfor `TestContextTransactionUtils.retrieveTransactionManager()`] for details on thealgorithm used to look up a transaction manager in the test's `ApplicationContext`.@@ -5295,8 +5295,8 @@ when using HTML-based views. This integration lets you:* Easily test HTML pages by using tools such ashttp://htmlunit.sourceforge.net/[HtmlUnit],http://seleniumhq.org/projects/webdriver/[WebDriver], and-http://www.gebish.org/manual/current/testing.html#spock_junit__testng[Geb] without the-need to deploy to a Servlet container.+http://www.gebish.org/manual/current/#spock-junit-testng[Geb] without the need to+deploy to a Servlet container.* Test JavaScript within pages.* Optionally, test using mock services to speed up testing.* Share logic between in-container end-to-end tests and out-of-container integration tests.src/docs/asciidoc/data-access.adoc | 46 +++++++++++++++++-------------1 file changed, 26 insertions(+), 20 deletions(-)
spring-beans/src/main/java/org/springframework/beans/factory/Aware.java+10 −12
@@ -1,5 +1,5 @@/*-* Copyright 2002-2011 the original author or authors.+* Copyright 2002-2018 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.@@ -17,21 +17,19 @@package org.springframework.beans.factory;/**-* Marker superinterface indicating that a bean is eligible to be-* notified by the Spring container of a particular framework object-* through a callback-style method. Actual method signature is-* determined by individual subinterfaces, but should typically-* consist of just one void-returning method that accepts a single-* argument.+* A marker superinterface indicating that a bean is eligible to be notified by the+* Spring container of a particular framework object through a callback-style method.+* The actual method signature is determined by individual subinterfaces but should+* typically consist of just one void-returning method that accepts a single argument.*-* <p>Note that merely implementing {@link Aware} provides no default-* functionality. Rather, processing must be done explicitly, for example-* in a {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}.+* <p>Note that merely implementing {@link Aware} provides no default functionality.+* Rather, processing must be done explicitly, for example in a+* {@link org.springframework.beans.factory.config.BeanPostProcessor}.* Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}-* and {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}-* for examples of processing {@code *Aware} interface callbacks.+* for an example of processing specific {@code *Aware} interface callbacks.** @author Chris Beams+* @author Juergen Hoeller* @since 3.1*/public interface Aware {
spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RequestPredicateAttributesTests.java+206 −0
@@ -0,0 +1,206 @@+/*+* Copyright 2002-2018 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.+* You may obtain a copy of the License at+*+* http://www.apache.org/licenses/LICENSE-2.0+*+* Unless required by applicable law or agreed to in writing, software+* distributed under the License is distributed on an "AS IS" BASIS,+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+* See the License for the specific language governing permissions and+* limitations under the License.+*/++package org.springframework.web.reactive.function.server;++import java.util.Collections;++import org.junit.Before;+import org.junit.Test;++import org.springframework.core.codec.StringDecoder;+import org.springframework.http.codec.DecoderHttpMessageReader;+import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;+import org.springframework.mock.web.test.server.MockServerWebExchange;++import static org.junit.Assert.*;++/**+* @author Arjen Poutsma+*/+public class RequestPredicateAttributesTests {++private DefaultServerRequest request;++@Before+public void createRequest() {+MockServerHttpRequest request = MockServerHttpRequest.get("http://example.com/path").build();+MockServerWebExchange webExchange = MockServerWebExchange.from(request);+webExchange.getAttributes().put("exchange", "bar");++this.request = new DefaultServerRequest(webExchange,+Collections.singletonList(+new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes())));+}+++@Test+public void negateSucceed() {+RequestPredicate predicate = new AddAttributePredicate(false, "predicate", "baz").negate();++boolean result = predicate.test(this.request);+assertTrue(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertEquals("baz", this.request.attributes().get("predicate"));+}++@Test+public void negateFail() {+RequestPredicate predicate = new AddAttributePredicate(true, "predicate", "baz").negate();++boolean result = predicate.test(this.request);+assertFalse(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertFalse(this.request.attributes().containsKey("baz"));+}++@Test+public void andBothSucceed() {+RequestPredicate left = new AddAttributePredicate(true, "left", "baz");+RequestPredicate right = new AddAttributePredicate(true, "right", "qux");+RequestPredicate predicate = new RequestPredicates.AndRequestPredicate(left, right);++boolean result = predicate.test(this.request);+assertTrue(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertEquals("baz", this.request.attributes().get("left"));+assertEquals("qux", this.request.attributes().get("right"));+}++@Test+public void andLeftSucceed() {+RequestPredicate left = new AddAttributePredicate(true, "left", "bar");+RequestPredicate right = new AddAttributePredicate(false, "right", "qux");+RequestPredicate predicate = new RequestPredicates.AndRequestPredicate(left, right);++boolean result = predicate.test(this.request);+assertFalse(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertFalse(this.request.attributes().containsKey("left"));+assertFalse(this.request.attributes().containsKey("right"));+}++@Test+public void andRightSucceed() {+RequestPredicate left = new AddAttributePredicate(false, "left", "bar");+RequestPredicate right = new AddAttributePredicate(true, "right", "qux");+RequestPredicate predicate = new RequestPredicates.AndRequestPredicate(left, right);++boolean result = predicate.test(this.request);+assertFalse(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertFalse(this.request.attributes().containsKey("left"));+assertFalse(this.request.attributes().containsKey("right"));+}++@Test+public void andBothFail() {+RequestPredicate left = new AddAttributePredicate(false, "left", "bar");+RequestPredicate right = new AddAttributePredicate(false, "right", "qux");+RequestPredicate predicate = new RequestPredicates.AndRequestPredicate(left, right);++boolean result = predicate.test(this.request);+assertFalse(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertFalse(this.request.attributes().containsKey("left"));+assertFalse(this.request.attributes().containsKey("right"));+}++@Test+public void orBothSucceed() {+RequestPredicate left = new AddAttributePredicate(true, "left", "baz");+RequestPredicate right = new AddAttributePredicate(true, "right", "qux");+RequestPredicate predicate = new RequestPredicates.OrRequestPredicate(left, right);++boolean result = predicate.test(this.request);+assertTrue(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertEquals("baz", this.request.attributes().get("left"));+assertFalse(this.request.attributes().containsKey("right"));+}++@Test+public void orLeftSucceed() {+RequestPredicate left = new AddAttributePredicate(true, "left", "baz");+RequestPredicate right = new AddAttributePredicate(false, "right", "qux");+RequestPredicate predicate = new RequestPredicates.OrRequestPredicate(left, right);++boolean result = predicate.test(this.request);+assertTrue(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertEquals("baz", this.request.attributes().get("left"));+assertFalse(this.request.attributes().containsKey("right"));+}++@Test+public void orRightSucceed() {+RequestPredicate left = new AddAttributePredicate(false, "left", "baz");+RequestPredicate right = new AddAttributePredicate(true, "right", "qux");+RequestPredicate predicate = new RequestPredicates.OrRequestPredicate(left, right);++boolean result = predicate.test(this.request);+assertTrue(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertFalse(this.request.attributes().containsKey("left"));+assertEquals("qux", this.request.attributes().get("right"));+}++@Test+public void orBothFail() {+RequestPredicate left = new AddAttributePredicate(false, "left", "baz");+RequestPredicate right = new AddAttributePredicate(false, "right", "qux");+RequestPredicate predicate = new RequestPredicates.OrRequestPredicate(left, right);++boolean result = predicate.test(this.request);+assertFalse(result);++assertEquals("bar", this.request.attributes().get("exchange"));+assertFalse(this.request.attributes().containsKey("baz"));+assertFalse(this.request.attributes().containsKey("quux"));+}+++private static class AddAttributePredicate implements RequestPredicate {++private boolean result;++private final String key;++private final String value;++private AddAttributePredicate(boolean result, String key, String value) {+this.result = result;+this.key = key;+this.value = value;+}++@Override+public boolean test(ServerRequest request) {+request.attributes().put(key, value);+return this.result;+}+}++}.../function/server/RouterFunctions.java | 7 +-.../DispatcherHandlerIntegrationTests.java | 96 +++++++++++++++++++2 files changed, 101 insertions(+), 2 deletions(-)create mode 100644 spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/DispatcherHandlerIntegrationTests.java
src/docs/asciidoc/data-access-appendix.adoc+14 −14
@@ -19,13 +19,12 @@ The `tx` tags deal with configuring all of those beans in Spring's comprehensivefor transactions. These tags are covered in the chapter entitled<<data-access.adoc#transaction,Transaction Management>>.-TIP: We strongly encourag you to look at the `'spring-tx.xsd'` file that ships with the+TIP: We strongly encourage you to look at the `'spring-tx.xsd'` file that ships with theSpring distribution. This file contains the XML Schema for Spring's transactionconfiguration and covers all of the various elements in the `tx` namespace, including-attribute defaults and similar information. This file is documented inline, and, thus, the-information is not repeated here in the interests of adhering to the DRY (Don't Repeat-Yourself) principle.-====+attribute defaults and similar information. This file is documented inline, and, thus,+the information is not repeated here in the interests of adhering to the DRY (Don't+Repeat Yourself) principle.In the interest of completeness, to use the elements in the `tx` schema, you need to havethe following preamble at the top of your Spring XML configuration file. The text in the@@ -51,10 +50,11 @@ are available to you:<2> Specify the location (with other schema locations).====-NOTE: Often, when you use the elements in the `tx` namespace, you are also using the elements from the-`aop` namespace (since the declarative transaction support in Spring is implemented-by using AOP). The preceding XML snippet contains the relevant lines needed to reference the-`aop` schema so that the elements in the `aop` namespace are available to you.+NOTE: Often, when you use the elements in the `tx` namespace, you are also using the+elements from the `aop` namespace (since the declarative transaction support in Spring is+implemented by using AOP). The preceding XML snippet contains the relevant lines needed+to reference the `aop` schema so that the elements in the `aop` namespace are available+to you.@@ -63,12 +63,12 @@ by using AOP). The preceding XML snippet contains the relevant lines needed to rThe `jdbc` elements let you quickly configure an embedded database or initialize anexisting data source. These elements are documented in-<<data-access.adoc#jdbc-embedded-database-support,Embedded Database Support>>-and <<data-access.adoc#jdbc-initializing-datasource,Initializing a DataSource>>, respectively.+<<data-access.adoc#jdbc-embedded-database-support,Embedded Database Support>> and+<<data-access.adoc#jdbc-initializing-datasource,Initializing a DataSource>>, respectively.-To use the elements in the `jdbc` schema, you need to have the following preamble at the top-of your Spring XML configuration file. The text in the following snippet references the-correct schema so that the elements in the `jdbc` namespace are available to you:+To use the elements in the `jdbc` schema, you need to have the following preamble at the+top of your Spring XML configuration file. The text in the following snippet references+the correct schema so that the elements in the `jdbc` namespace are available to you:====[source,xml,indent=0]
spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java+13 −7
@@ -23,15 +23,21 @@import java.lang.annotation.Target;/**-* Marks a constructor, field, setter method or config method as to be autowired-* by Spring's dependency injection facilities.+* Marks a constructor, field, setter method or config method as to be autowired by+* Spring's dependency injection facilities.*-* <p>Only one constructor (at max) of any given bean class may carry this annotation,-* indicating the constructor to autowire when used as a Spring bean. Such a-* constructor does not have to be public.+* <p>Only one constructor (at max) of any given bean class may declare this annotation+* with the 'required' parameter set to {@code true}, indicating <i>the</i> constructor+* to autowire when used as a Spring bean. If multiple <i>non-required</i> constructors+* declare the annotation, they will be considered as candidates for autowiring.+* The constructor with the greatest number of dependencies that can be satisfied by+* matching beans in the Spring container will be chosen. If none of the candidates+* can be satisfied, then a primary/default constructor (if present) will be used.+* If a class only declares a single constructor to begin with, it will always be used,+* even if not annotated. An annotated constructor does not have to be public.*-* <p>Fields are injected right after construction of a bean, before any config-* methods are invoked. Such a config field does not have to be public.+* <p>Fields are injected right after construction of a bean, before any config methods+* are invoked. Such a config field does not have to be public.** <p>Config methods may have an arbitrary name and any number of arguments; each of* those arguments will be autowired with a matching bean in the Spring container.
spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java+10 −34
@@ -18,13 +18,11 @@import java.util.ArrayList;import java.util.Arrays;-import java.util.Collections;import java.util.List;import java.util.function.Consumer;import java.util.stream.Collectors;import org.springframework.beans.factory.NoSuchBeanDefinitionException;-import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.core.annotation.AnnotationAwareOrderComparator;import org.springframework.http.codec.ServerCodecConfigurer;@@ -158,12 +156,16 @@ public static WebHttpHandlerBuilder applicationContext(ApplicationContext contexWebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context);-// Autowire lists for @Bean + @Order--SortedBeanContainer container = new SortedBeanContainer();-context.getAutowireCapableBeanFactory().autowireBean(container);-builder.filters(filters -> filters.addAll(container.getFilters()));-builder.exceptionHandlers(handlers -> handlers.addAll(container.getExceptionHandlers()));+List<WebFilter> webFilters = context+.getBeanProvider(WebFilter.class)+.orderedStream()+.collect(Collectors.toList());+builder.filters(filters -> filters.addAll(webFilters));+List<WebExceptionHandler> exceptionHandlers = context+.getBeanProvider(WebExceptionHandler.class)+.orderedStream()+.collect(Collectors.toList());+builder.exceptionHandlers(handlers -> handlers.addAll(exceptionHandlers));try {builder.sessionManager(@@ -389,30 +391,4 @@ public WebHttpHandlerBuilder clone() {return new WebHttpHandlerBuilder(this);}--private static class SortedBeanContainer {--private List<WebFilter> filters = Collections.emptyList();--private List<WebExceptionHandler> exceptionHandlers = Collections.emptyList();--@Autowired(required = false)-public void setFilters(List<WebFilter> filters) {-this.filters = filters;-}--public List<WebFilter> getFilters() {-return this.filters;-}--@Autowired(required = false)-public void setExceptionHandlers(List<WebExceptionHandler> exceptionHandlers) {-this.exceptionHandlers = exceptionHandlers;-}--public List<WebExceptionHandler> getExceptionHandlers() {-return this.exceptionHandlers;-}-}-}
Release delta 5.0.0.RELEASE → 5.0.10.RELEASE (contains the fix)
spring-web/src/test/java/org/springframework/web/cors/reactive/CorsWebFilterTests.java+44 −17
@@ -1,24 +1,46 @@+/*+* Copyright 2002-2017 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.+* You may obtain a copy of the License at+*+* http://www.apache.org/licenses/LICENSE-2.0+*+* Unless required by applicable law or agreed to in writing, software+* distributed under the License is distributed on an "AS IS" BASIS,+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+* See the License for the specific language governing permissions and+* limitations under the License.+*/package org.springframework.web.cors.reactive;import java.io.IOException;import java.util.Arrays;-import javax.servlet.ServletException;import org.junit.Before;import org.junit.Test;import reactor.core.publisher.Mono;+import org.springframework.http.HttpHeaders;import org.springframework.http.HttpMethod;import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;-import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.server.WebFilterChain;import static org.junit.Assert.assertEquals;import static org.junit.Assert.assertNull;-import static org.springframework.http.HttpHeaders.*;+import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS;+import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;+import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS;+import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_MAX_AGE;+import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS;+import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD;+import static org.springframework.http.HttpHeaders.HOST;+import static org.springframework.http.HttpHeaders.ORIGIN;/*** Unit tests for {@link CorsWebFilter}.@@ -50,19 +72,19 @@ public void validActualRequest() {.header(ORIGIN, "http://domain2.com").header("header2", "foo").build();-MockServerWebExchange exchange = new MockServerWebExchange(request);WebFilterChain filterChain = (filterExchange) -> {try {-assertEquals("http://domain2.com", filterExchange.getResponse().getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));-assertEquals("header3, header4", filterExchange.getResponse().getHeaders().getFirst(ACCESS_CONTROL_EXPOSE_HEADERS));+HttpHeaders headers = filterExchange.getResponse().getHeaders();+assertEquals("http://domain2.com", headers.getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));+assertEquals("header3, header4", headers.getFirst(ACCESS_CONTROL_EXPOSE_HEADERS));} catch (AssertionError ex) {return Mono.error(ex);}return Mono.empty();};-filter.filter(exchange, filterChain);+filter.filter(MockServerWebExchange.from(request), filterChain);}@Test@@ -74,9 +96,10 @@ public void invalidActualRequest() throws ServletException, IOException {.header(ORIGIN, "http://domain2.com").header("header2", "foo").build();-MockServerWebExchange exchange = new MockServerWebExchange(request);+MockServerWebExchange exchange = MockServerWebExchange.from(request);-WebFilterChain filterChain = (filterExchange) -> Mono.error(new AssertionError("Invalid requests must not be forwarded to the filter chain"));+WebFilterChain filterChain = (filterExchange) -> Mono.error(+new AssertionError("Invalid requests must not be forwarded to the filter chain"));filter.filter(exchange, filterChain);assertNull(exchange.getResponse().getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));@@ -92,15 +115,17 @@ public void validPreFlightRequest() throws ServletException, IOException {.header(ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.GET.name()).header(ACCESS_CONTROL_REQUEST_HEADERS, "header1, header2").build();-MockServerWebExchange exchange = new MockServerWebExchange(request);+MockServerWebExchange exchange = MockServerWebExchange.from(request);-WebFilterChain filterChain = (filterExchange) -> Mono.error(new AssertionError("Preflight requests must not be forwarded to the filter chain"));+WebFilterChain filterChain = (filterExchange) -> Mono.error(+new AssertionError("Preflight requests must not be forwarded to the filter chain"));filter.filter(exchange, filterChain);-assertEquals("http://domain2.com", exchange.getResponse().getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));-assertEquals("header1, header2", exchange.getResponse().getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS));-assertEquals("header3, header4", exchange.getResponse().getHeaders().getFirst(ACCESS_CONTROL_EXPOSE_HEADERS));-assertEquals(123L, Long.parseLong(exchange.getResponse().getHeaders().getFirst(ACCESS_CONTROL_MAX_AGE)));+HttpHeaders headers = exchange.getResponse().getHeaders();+assertEquals("http://domain2.com", headers.getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));+assertEquals("header1, header2", headers.getFirst(ACCESS_CONTROL_ALLOW_HEADERS));+assertEquals("header3, header4", headers.getFirst(ACCESS_CONTROL_EXPOSE_HEADERS));+assertEquals(123L, Long.parseLong(headers.getFirst(ACCESS_CONTROL_MAX_AGE)));}@Test@@ -113,9 +138,11 @@ public void invalidPreFlightRequest() throws ServletException, IOException {.header(ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.DELETE.name()).header(ACCESS_CONTROL_REQUEST_HEADERS, "header1, header2").build();-MockServerWebExchange exchange = new MockServerWebExchange(request);+MockServerWebExchange exchange = MockServerWebExchange.from(request);++WebFilterChain filterChain = (filterExchange) -> Mono.error(+new AssertionError("Preflight requests must not be forwarded to the filter chain"));-WebFilterChain filterChain = (filterExchange) -> Mono.error(new AssertionError("Preflight requests must not be forwarded to the filter chain"));filter.filter(exchange, filterChain);assertNull(exchange.getResponse().getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));
spring-webflux/src/test/java/org/springframework/web/reactive/result/HandlerResultHandlerTests.java+15 −9
@@ -25,14 +25,20 @@import org.springframework.core.ReactiveAdapterRegistry;import org.springframework.http.MediaType;import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;-import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.web.reactive.HandlerMapping;import org.springframework.web.reactive.accept.FixedContentTypeResolver;import org.springframework.web.reactive.accept.HeaderContentTypeResolver;import org.springframework.web.reactive.accept.RequestedContentTypeResolver;-import static org.junit.Assert.*;-import static org.springframework.http.MediaType.*;+import static org.junit.Assert.assertEquals;+import static org.springframework.http.MediaType.ALL;+import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8;+import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM;+import static org.springframework.http.MediaType.IMAGE_GIF;+import static org.springframework.http.MediaType.IMAGE_JPEG;+import static org.springframework.http.MediaType.IMAGE_PNG;+import static org.springframework.http.MediaType.TEXT_PLAIN;/*** Unit tests for {@link HandlerResultHandlerSupport}.@@ -48,7 +54,7 @@ public class HandlerResultHandlerTests {public void usesContentTypeResolver() throws Exception {TestResultHandler resultHandler = new TestResultHandler(new FixedContentTypeResolver(IMAGE_GIF));List<MediaType> mediaTypes = Arrays.asList(IMAGE_JPEG, IMAGE_GIF, IMAGE_PNG);-MockServerWebExchange exchange = MockServerHttpRequest.get("/path").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/path").build());MediaType actual = resultHandler.selectMediaType(exchange, () -> mediaTypes);assertEquals(IMAGE_GIF, actual);@@ -56,7 +62,7 @@ public void usesContentTypeResolver() throws Exception {@Testpublic void producibleMediaTypesRequestAttribute() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("/path").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/path").build());exchange.getAttributes().put(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, Collections.singleton(IMAGE_GIF));List<MediaType> mediaTypes = Arrays.asList(IMAGE_JPEG, IMAGE_GIF, IMAGE_PNG);@@ -67,9 +73,9 @@ public void producibleMediaTypesRequestAttribute() throws Exception {@Test // SPR-9160public void sortsByQuality() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("/path")+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/path").header("Accept", "text/plain; q=0.5, application/json")-.toExchange();+.build());List<MediaType> mediaTypes = Arrays.asList(TEXT_PLAIN, APPLICATION_JSON_UTF8);MediaType actual = this.resultHandler.selectMediaType(exchange, () -> mediaTypes);@@ -81,7 +87,7 @@ public void sortsByQuality() throws Exception {public void charsetFromAcceptHeader() throws Exception {MediaType text8859 = MediaType.parseMediaType("text/plain;charset=ISO-8859-1");MediaType textUtf8 = MediaType.parseMediaType("text/plain;charset=UTF-8");-MockServerWebExchange exchange = MockServerHttpRequest.get("/path").accept(text8859).toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/path").accept(text8859).build());MediaType actual = this.resultHandler.selectMediaType(exchange, () -> Collections.singletonList(textUtf8));assertEquals(text8859, actual);@@ -90,7 +96,7 @@ public void charsetFromAcceptHeader() throws Exception {@Test // SPR-12894public void noConcreteMediaType() throws Exception {List<MediaType> producible = Collections.singletonList(ALL);-MockServerWebExchange exchange = MockServerHttpRequest.get("/path").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/path").build());MediaType actual = this.resultHandler.selectMediaType(exchange, () -> producible);assertEquals(APPLICATION_OCTET_STREAM, actual);
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java+14 −6
@@ -46,6 +46,8 @@import org.springframework.http.codec.HttpMessageReader;import org.springframework.http.codec.json.Jackson2JsonDecoder;import org.springframework.lang.Nullable;+import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.validation.Errors;import org.springframework.validation.Validator;import org.springframework.validation.annotation.Validated;@@ -57,9 +59,12 @@import org.springframework.web.server.ServerWebInputException;import org.springframework.web.server.UnsupportedMediaTypeStatusException;-import static org.junit.Assert.*;-import static org.springframework.core.ResolvableType.*;-import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.*;+import static org.junit.Assert.assertArrayEquals;+import static org.junit.Assert.assertEquals;+import static org.junit.Assert.assertNotNull;+import static org.junit.Assert.assertTrue;+import static org.springframework.core.ResolvableType.forClassWithGenerics;+import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.post;/*** Unit tests for {@link AbstractMessageReaderArgumentResolver}.@@ -86,7 +91,8 @@ public void setup() throws Exception {@SuppressWarnings("unchecked")@Testpublic void missingContentType() throws Exception {-ServerWebExchange exchange = post("/path").body("{\"bar\":\"BARBAR\",\"foo\":\"FOOFOO\"}").toExchange();+MockServerHttpRequest request = post("/path").body("{\"bar\":\"BARBAR\",\"foo\":\"FOOFOO\"}");+ServerWebExchange exchange = MockServerWebExchange.from(request);ResolvableType type = forClassWithGenerics(Mono.class, TestBean.class);MethodParameter param = this.testMethod.arg(type);Mono<Object> result = this.resolver.readBody(param, true, this.bindingContext, exchange);@@ -99,7 +105,8 @@ public void missingContentType() throws Exception {@Test @SuppressWarnings("unchecked") // SPR-9942public void emptyBody() throws Exception {-ServerWebExchange exchange = post("/path").contentType(MediaType.APPLICATION_JSON).toExchange();+MockServerHttpRequest request = post("/path").contentType(MediaType.APPLICATION_JSON).build();+ServerWebExchange exchange = MockServerWebExchange.from(request);ResolvableType type = forClassWithGenerics(Mono.class, TestBean.class);MethodParameter param = this.testMethod.arg(type);Mono<TestBean> result = (Mono<TestBean>) this.resolver.readBody(@@ -292,7 +299,8 @@ public void parameterizedMethodArgument() throws Exception {@SuppressWarnings("unchecked")private <T> T resolveValue(MethodParameter param, String body) {-ServerWebExchange exchange = post("/path").contentType(MediaType.APPLICATION_JSON).body(body).toExchange();+MockServerHttpRequest request = post("/path").contentType(MediaType.APPLICATION_JSON).body(body);+ServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Object> result = this.resolver.readBody(param, true, this.bindingContext, exchange);Object value = result.block(Duration.ofSeconds(5));
spring-webflux/src/test/java/org/springframework/web/reactive/resource/ResourceWebHandlerTests.java+44 −32
@@ -47,7 +47,7 @@import org.springframework.http.server.PathContainer;import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;-import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.util.StringUtils;import org.springframework.web.reactive.HandlerMapping;import org.springframework.web.server.MethodNotAllowedException;@@ -90,7 +90,7 @@ public void setup() throws Exception {@Testpublic void getResource() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "foo.css");this.handler.handle(exchange).block(TIMEOUT);@@ -107,7 +107,7 @@ public void getResource() throws Exception {@Testpublic void getResourceHttpHeader() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.head("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.head("").build());setPathWithinHandlerMapping(exchange, "foo.css");this.handler.handle(exchange).block(TIMEOUT);@@ -128,7 +128,7 @@ public void getResourceHttpHeader() throws Exception {@Testpublic void getResourceHttpOptions() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.options("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.options("").build());setPathWithinHandlerMapping(exchange, "foo.css");this.handler.handle(exchange).block(TIMEOUT);@@ -138,7 +138,7 @@ public void getResourceHttpOptions() throws Exception {@Testpublic void getResourceNoCache() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "foo.css");this.handler.setCacheControl(CacheControl.noStore());this.handler.handle(exchange).block(TIMEOUT);@@ -158,7 +158,7 @@ public void getVersionedResource() throws Exception {this.handler.setResourceResolvers(Arrays.asList(versionResolver, new PathResourceResolver()));this.handler.afterPropertiesSet();-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "versionString/foo.css");this.handler.handle(exchange).block(TIMEOUT);@@ -169,7 +169,7 @@ public void getVersionedResource() throws Exception {@Testpublic void getResourceWithHtmlMediaType() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "foo.html");this.handler.handle(exchange).block(TIMEOUT);@@ -184,7 +184,7 @@ public void getResourceWithHtmlMediaType() throws Exception {@Testpublic void getResourceFromAlternatePath() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "baz.css");this.handler.handle(exchange).block(TIMEOUT);@@ -201,21 +201,23 @@ public void getResourceFromAlternatePath() throws Exception {@Testpublic void getResourceFromSubDirectory() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "js/foo.js");this.handler.handle(exchange).block(TIMEOUT);-assertEquals(MediaType.parseMediaType("application/javascript"), exchange.getResponse().getHeaders().getContentType());+assertEquals(MediaType.parseMediaType("application/javascript"),+exchange.getResponse().getHeaders().getContentType());assertResponseBody(exchange, "function foo() { console.log(\"hello world\"); }");}@Testpublic void getResourceFromSubDirectoryOfAlternatePath() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "js/baz.js");this.handler.handle(exchange).block(TIMEOUT);-assertEquals(MediaType.parseMediaType("application/javascript"), exchange.getResponse().getHeaders().getContentType());+HttpHeaders headers = exchange.getResponse().getHeaders();+assertEquals(MediaType.parseMediaType("application/javascript"), headers.getContentType());assertResponseBody(exchange, "function foo() { console.log(\"hello world\"); }");}@@ -226,8 +228,8 @@ public void getMediaTypeWithFavorPathExtensionOff() throws Exception {handler.setLocations(paths);handler.afterPropertiesSet();-MockServerWebExchange exchange = MockServerHttpRequest.get("")-.header("Accept", "application/json,text/plain,*/*").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("")+.header("Accept", "application/json,text/plain,*/*").build());setPathWithinHandlerMapping(exchange, "foo.html");handler.handle(exchange).block(TIMEOUT);@@ -268,7 +270,8 @@ private void testInvalidPath(HttpMethod httpMethod) throws Exception {}private void testInvalidPath(HttpMethod httpMethod, String requestPath, Resource location) throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.method(httpMethod, "").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.method(httpMethod, "").build();+ServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, requestPath);this.handler.handle(exchange).block(TIMEOUT);if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) {@@ -337,8 +340,8 @@ public void initAllowedLocationsWithExplicitConfiguration() throws Exception {@Testpublic void notModified() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("")-.ifModifiedSince(resourceLastModified("test/foo.css")).toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("")+.ifModifiedSince(resourceLastModified("test/foo.css")).build());setPathWithinHandlerMapping(exchange, "foo.css");this.handler.handle(exchange).block(TIMEOUT);assertEquals(HttpStatus.NOT_MODIFIED, exchange.getResponse().getStatusCode());@@ -347,7 +350,8 @@ public void notModified() throws Exception {@Testpublic void modified() throws Exception {long timestamp = resourceLastModified("test/foo.css") / 1000 * 1000 - 1;-MockServerWebExchange exchange = MockServerHttpRequest.get("").ifModifiedSince(timestamp).toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("").ifModifiedSince(timestamp).build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, "foo.css");this.handler.handle(exchange).block(TIMEOUT);@@ -357,7 +361,7 @@ public void modified() throws Exception {@Testpublic void directory() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "js/");this.handler.handle(exchange).block(TIMEOUT);assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode());@@ -365,7 +369,7 @@ public void directory() throws Exception {@Testpublic void directoryInJarFile() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "underscorejs/");this.handler.handle(exchange).block(TIMEOUT);@@ -375,7 +379,7 @@ public void directoryInJarFile() throws Exception {@Testpublic void missingResourcePath() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());setPathWithinHandlerMapping(exchange, "");this.handler.handle(exchange).block(TIMEOUT);assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode());@@ -383,13 +387,13 @@ public void missingResourcePath() throws Exception {@Test(expected = IllegalArgumentException.class)public void noPathWithinHandlerMappingAttribute() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());this.handler.handle(exchange).block(TIMEOUT);}@Test(expected = MethodNotAllowedException.class)public void unsupportedHttpMethod() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.post("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("").build());setPathWithinHandlerMapping(exchange, "foo.css");this.handler.handle(exchange).block(TIMEOUT);}@@ -402,7 +406,8 @@ public void resourceNotFound() throws Exception {}private void resourceNotFound(HttpMethod httpMethod) throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.method(httpMethod, "").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.method(httpMethod, "").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, "not-there.css");this.handler.handle(exchange).block(TIMEOUT);assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode());@@ -410,7 +415,8 @@ private void resourceNotFound(HttpMethod httpMethod) throws Exception {@Testpublic void partialContentByteRange() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").header("Range", "bytes=0-1").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("").header("Range", "bytes=0-1").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, "foo.txt");this.handler.handle(exchange).block(TIMEOUT);@@ -425,7 +431,8 @@ public void partialContentByteRange() throws Exception {@Testpublic void partialContentByteRangeNoEnd() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").header("range", "bytes=9-").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=9-").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, "foo.txt");this.handler.handle(exchange).block(TIMEOUT);@@ -440,7 +447,8 @@ public void partialContentByteRangeNoEnd() throws Exception {@Testpublic void partialContentByteRangeLargeEnd() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").header("range", "bytes=9-10000").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=9-10000").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, "foo.txt");this.handler.handle(exchange).block(TIMEOUT);@@ -455,7 +463,8 @@ public void partialContentByteRangeLargeEnd() throws Exception {@Testpublic void partialContentSuffixRange() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").header("range", "bytes=-1").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=-1").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, "foo.txt");this.handler.handle(exchange).block(TIMEOUT);@@ -470,7 +479,8 @@ public void partialContentSuffixRange() throws Exception {@Testpublic void partialContentSuffixRangeLargeSuffix() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").header("range", "bytes=-11").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=-11").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, "foo.txt");this.handler.handle(exchange).block(TIMEOUT);@@ -485,7 +495,8 @@ public void partialContentSuffixRangeLargeSuffix() throws Exception {@Testpublic void partialContentInvalidRangeHeader() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").header("range", "bytes=foo bar").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("").header("range", "bytes=foo bar").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, "foo.txt");StepVerifier.create(this.handler.handle(exchange))@@ -499,7 +510,8 @@ public void partialContentInvalidRangeHeader() throws Exception {@Testpublic void partialContentMultipleByteRanges() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").header("Range", "bytes=0-1, 4-5, 8-9").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("").header("Range", "bytes=0-1, 4-5, 8-9").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);setPathWithinHandlerMapping(exchange, "foo.txt");this.handler.handle(exchange).block(TIMEOUT);@@ -542,7 +554,7 @@ public void partialContentMultipleByteRanges() throws Exception {@Test // SPR-14005public void doOverwriteExistingCacheControlHeaders() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("").build());exchange.getResponse().getHeaders().setCacheControl(CacheControl.noStore().getHeaderValue());setPathWithinHandlerMapping(exchange, "foo.css");this.handler.handle(exchange).block(TIMEOUT);
spring-webflux/src/test/java/org/springframework/web/reactive/resource/CssLinkResourceTransformerTests.java+7 −6
@@ -33,7 +33,7 @@import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;-import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.util.StringUtils;import static org.junit.Assert.assertEquals;@@ -76,7 +76,8 @@ public void setup() {@Testpublic void transform() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("/static/main.css").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/static/main.css").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);Resource css = new ClassPathResource("test/main.css", getClass());String expected = "\n" +@@ -98,7 +99,7 @@ public void transform() throws Exception {@Testpublic void transformNoLinks() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("/static/foo.css").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/static/foo.css").build());Resource expected = new ClassPathResource("test/foo.css", getClass());StepVerifier.create(this.transformerChain.transform(exchange, expected)).consumeNextWith(resource -> assertSame(expected, resource))@@ -107,7 +108,7 @@ public void transformNoLinks() throws Exception {@Testpublic void transformExtLinksNotAllowed() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("/static/external.css").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/static/external.css").build());ResourceResolverChain resolverChain = Mockito.mock(DefaultResourceResolverChain.class);ResourceTransformerChain transformerChain = new DefaultResourceTransformerChain(resolverChain,Collections.singletonList(new CssLinkResourceTransformer()));@@ -133,7 +134,7 @@ public void transformExtLinksNotAllowed() throws Exception {@Testpublic void transformWithNonCssResource() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("/static/images/image.png").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/static/images/image.png").build());Resource expected = new ClassPathResource("test/images/image.png", getClass());StepVerifier.create(this.transformerChain.transform(exchange, expected)).expectNext(expected)@@ -142,7 +143,7 @@ public void transformWithNonCssResource() throws Exception {@Testpublic void transformWithGzippedResource() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("/static/main.css").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/static/main.css").build());Resource original = new ClassPathResource("test/main.css", getClass());createTempCopy("main.css", "main.css.gz");GzipResourceResolver.GzippedResource expected = new GzipResourceResolver.GzippedResource(original);
spring-test/src/main/java/org/springframework/mock/web/server/MockServerWebExchange.java+20 −12
@@ -13,32 +13,30 @@* See the License for the specific language governing permissions and* limitations under the License.*/-package org.springframework.mock.http.server.reactive;+package org.springframework.mock.web.server;import org.springframework.http.codec.ServerCodecConfigurer;-import org.springframework.web.server.ServerWebExchangeDecorator;+import org.springframework.mock.http.server.reactive.MockServerHttpRequest;+import org.springframework.mock.http.server.reactive.MockServerHttpResponse;import org.springframework.web.server.adapter.DefaultServerWebExchange;import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;import org.springframework.web.server.session.DefaultWebSessionManager;/**-* {@code ServerWebExchange} for use in tests.+* Variant of {@link DefaultServerWebExchange} for use in tests with+* {@link MockServerHttpRequest} and {@link MockServerHttpResponse}.*-* <p>Effectively a wrapper around {@link DefaultServerWebExchange} plugged in-* with {@link MockServerHttpRequest} and {@link MockServerHttpResponse}.-*-* <p>Typically used via {@link MockServerHttpRequest#toExchange()}.+* <p>See static factory methods to create an instance.** @author Rossen Stoyanchev* @since 5.0*/-public class MockServerWebExchange extends ServerWebExchangeDecorator {+public final class MockServerWebExchange extends DefaultServerWebExchange {-public MockServerWebExchange(MockServerHttpRequest request) {-super(new DefaultServerWebExchange(-request, new MockServerHttpResponse(), new DefaultWebSessionManager(),-ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver()));+private MockServerWebExchange(MockServerHttpRequest request) {+super(request, new MockServerHttpResponse(), new DefaultWebSessionManager(),+ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());}@@ -47,4 +45,14 @@ public MockServerHttpResponse getResponse() {return (MockServerHttpResponse) super.getResponse();}++/**+* Create a {@link MockServerWebExchange} from the given request.+* @param request the request to use.+* @return the exchange+*/+public static MockServerWebExchange from(MockServerHttpRequest request) {+return new MockServerWebExchange(request);+}+}
spring-web/src/test/java/org/springframework/mock/web/test/server/MockServerWebExchange.java+20 −12
@@ -13,32 +13,30 @@* See the License for the specific language governing permissions and* limitations under the License.*/-package org.springframework.mock.http.server.reactive.test;+package org.springframework.mock.web.test.server;import org.springframework.http.codec.ServerCodecConfigurer;-import org.springframework.web.server.ServerWebExchangeDecorator;+import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;+import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;import org.springframework.web.server.adapter.DefaultServerWebExchange;import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;import org.springframework.web.server.session.DefaultWebSessionManager;/**-* {@code ServerWebExchange} for use in tests.+* Variant of {@link DefaultServerWebExchange} for use in tests with+* {@link MockServerHttpRequest} and {@link MockServerHttpResponse}.*-* <p>Effectively a wrapper around {@link DefaultServerWebExchange} plugged in-* with {@link MockServerHttpRequest} and {@link MockServerHttpResponse}.-*-* <p>Typically used via {@link MockServerHttpRequest#toExchange()}.+* <p>See static factory methods to create an instance.** @author Rossen Stoyanchev* @since 5.0*/-public class MockServerWebExchange extends ServerWebExchangeDecorator {+public final class MockServerWebExchange extends DefaultServerWebExchange {-public MockServerWebExchange(MockServerHttpRequest request) {-super(new DefaultServerWebExchange(-request, new MockServerHttpResponse(), new DefaultWebSessionManager(),-ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver()));+private MockServerWebExchange(MockServerHttpRequest request) {+super(request, new MockServerHttpResponse(), new DefaultWebSessionManager(),+ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());}@@ -47,4 +45,14 @@ public MockServerHttpResponse getResponse() {return (MockServerHttpResponse) super.getResponse();}++/**+* Create a {@link MockServerWebExchange} from the given request.+* @param request the request to use.+* @return the exchange+*/+public static MockServerWebExchange from(MockServerHttpRequest request) {+return new MockServerWebExchange(request);+}+}
spring-webflux/src/test/java/org/springframework/web/reactive/DispatcherHandlerErrorTests.java+19 −13
@@ -33,6 +33,7 @@import org.springframework.http.HttpStatus;import org.springframework.http.codec.EncoderHttpMessageWriter;import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;@@ -51,8 +52,10 @@import static org.hamcrest.CoreMatchers.instanceOf;import static org.hamcrest.CoreMatchers.startsWith;import static org.hamcrest.Matchers.is;-import static org.junit.Assert.*;-import static org.springframework.http.MediaType.*;+import static org.junit.Assert.assertEquals;+import static org.junit.Assert.assertSame;+import static org.junit.Assert.assertThat;+import static org.springframework.http.MediaType.APPLICATION_JSON;/*** Test the effect of exceptions at different stages of request processing by@@ -79,7 +82,8 @@ public void setup() throws Exception {@Testpublic void noHandler() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.get("/does-not-exist").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/does-not-exist").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Void> publisher = this.dispatcherHandler.handle(exchange);StepVerifier.create(publisher)@@ -92,7 +96,8 @@ public void noHandler() throws Exception {@Testpublic void controllerReturnsMonoError() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.get("/error-signal").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/error-signal").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Void> publisher = this.dispatcherHandler.handle(exchange);StepVerifier.create(publisher)@@ -102,7 +107,8 @@ public void controllerReturnsMonoError() throws Exception {@Testpublic void controllerThrowsException() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.get("/raise-exception").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/raise-exception").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Void> publisher = this.dispatcherHandler.handle(exchange);StepVerifier.create(publisher)@@ -112,7 +118,8 @@ public void controllerThrowsException() throws Exception {@Testpublic void unknownReturnType() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.get("/unknown-return-type").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/unknown-return-type").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Void> publisher = this.dispatcherHandler.handle(exchange);StepVerifier.create(publisher)@@ -125,9 +132,8 @@ public void unknownReturnType() throws Exception {@Testpublic void responseBodyMessageConversionError() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.post("/request-body")-.accept(APPLICATION_JSON).body("body")-.toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(+MockServerHttpRequest.post("/request-body").accept(APPLICATION_JSON).body("body"));Mono<Void> publisher = this.dispatcherHandler.handle(exchange);@@ -138,9 +144,8 @@ public void responseBodyMessageConversionError() throws Exception {@Testpublic void requestBodyError() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.post("/request-body")-.body(Mono.error(EXCEPTION))-.toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(+MockServerHttpRequest.post("/request-body").body(Mono.error(EXCEPTION)));Mono<Void> publisher = this.dispatcherHandler.handle(exchange);@@ -151,7 +156,8 @@ public void requestBodyError() throws Exception {@Testpublic void webExceptionHandler() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.get("/unknown-argument-type").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(+MockServerHttpRequest.get("/unknown-argument-type").build());List<WebExceptionHandler> handlers = Collections.singletonList(new ServerError500ExceptionHandler());WebHandler webHandler = new ExceptionHandlingWebHandler(this.dispatcherHandler, handlers);
spring-webflux/src/test/java/org/springframework/web/reactive/resource/AppCacheManifestTransformerTests.java+7 −4
@@ -30,8 +30,8 @@import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.util.FileCopyUtils;-import org.springframework.web.server.ServerWebExchange;import static org.junit.Assert.assertEquals;import static org.junit.Assert.assertThat;@@ -79,7 +79,8 @@ public void setup() {@Testpublic void noTransformIfExtensionNoMatch() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.get("/static/foobar.file").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/static/foobar.file").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);this.chain = mock(ResourceTransformerChain.class);Resource resource = mock(Resource.class);given(resource.getFilename()).willReturn("foobar.file");@@ -91,7 +92,8 @@ public void noTransformIfExtensionNoMatch() throws Exception {@Testpublic void syntaxErrorInManifest() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.get("/static/error.appcache").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/static/error.appcache").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);this.chain = mock(ResourceTransformerChain.class);Resource resource = new ClassPathResource("test/error.appcache", getClass());given(this.chain.transform(exchange, resource)).willReturn(Mono.just(resource));@@ -102,7 +104,8 @@ public void syntaxErrorInManifest() throws Exception {@Testpublic void transformManifest() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.get("/static/test.appcache").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/static/test.appcache").build();+MockServerWebExchange exchange = MockServerWebExchange.from(request);VersionResourceResolver versionResolver = new VersionResourceResolver();versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolverTests.java+21 −11
@@ -33,7 +33,7 @@import org.springframework.core.annotation.SynthesizingMethodParameter;import org.springframework.format.support.DefaultFormattingConversionService;import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;-import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.util.ReflectionUtils;import org.springframework.web.bind.annotation.RequestHeader;import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;@@ -41,7 +41,11 @@import org.springframework.web.server.ServerWebExchange;import org.springframework.web.server.ServerWebInputException;-import static org.junit.Assert.*;+import static org.junit.Assert.assertArrayEquals;+import static org.junit.Assert.assertEquals;+import static org.junit.Assert.assertFalse;+import static org.junit.Assert.assertTrue;+import static org.junit.Assert.fail;/*** Unit tests for {@link RequestHeaderMethodArgumentResolver}.@@ -108,7 +112,7 @@ public void supportsParameter() {@Testpublic void resolveStringArgument() throws Exception {String expected = "foo";-ServerWebExchange exchange = MockServerHttpRequest.get("/").header("name", expected).toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").header("name", expected).build());Mono<Object> mono = this.resolver.resolveArgument(this.paramNamedDefaultValueStringHeader, this.bindingContext, exchange);@@ -120,7 +124,8 @@ public void resolveStringArgument() throws Exception {@Testpublic void resolveStringArrayArgument() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.get("/").header("name", "foo", "bar").toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/").header("name", "foo", "bar").build();+ServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Object> mono = this.resolver.resolveArgument(this.paramNamedValueStringArray, this.bindingContext, exchange);@@ -132,7 +137,7 @@ public void resolveStringArrayArgument() throws Exception {@Testpublic void resolveDefaultValue() throws Exception {-MockServerWebExchange exchange = MockServerHttpRequest.get("/").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").build());Mono<Object> mono = this.resolver.resolveArgument(this.paramNamedDefaultValueStringHeader, this.bindingContext, exchange);@@ -147,7 +152,7 @@ public void resolveDefaultValueFromSystemProperty() throws Exception {try {Mono<Object> mono = this.resolver.resolveArgument(this.paramSystemProperty, this.bindingContext,-MockServerHttpRequest.get("/").toExchange());+MockServerWebExchange.from(MockServerHttpRequest.get("/").build()));Object result = mono.block();assertTrue(result instanceof String);@@ -161,7 +166,8 @@ public void resolveDefaultValueFromSystemProperty() throws Exception {@Testpublic void resolveNameFromSystemPropertyThroughExpression() throws Exception {String expected = "foo";-ServerWebExchange exchange = MockServerHttpRequest.get("/").header("bar", expected).toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/").header("bar", expected).build();+ServerWebExchange exchange = MockServerWebExchange.from(request);System.setProperty("systemProperty", "bar");try {@@ -180,7 +186,8 @@ public void resolveNameFromSystemPropertyThroughExpression() throws Exception {@Testpublic void resolveNameFromSystemPropertyThroughPlaceholder() throws Exception {String expected = "foo";-ServerWebExchange exchange = MockServerHttpRequest.get("/").header("bar", expected).toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/").header("bar", expected).build();+ServerWebExchange exchange = MockServerWebExchange.from(request);System.setProperty("systemProperty", "bar");try {@@ -200,7 +207,7 @@ public void resolveNameFromSystemPropertyThroughPlaceholder() throws Exception {public void notFound() throws Exception {Mono<Object> mono = resolver.resolveArgument(this.paramNamedValueStringArray, this.bindingContext,-MockServerHttpRequest.get("/").toExchange());+MockServerWebExchange.from(MockServerHttpRequest.get("/").build()));StepVerifier.create(mono).expectNextCount(0)@@ -212,7 +219,8 @@ public void notFound() throws Exception {@SuppressWarnings("deprecation")public void dateConversion() throws Exception {String rfc1123val = "Thu, 21 Apr 2016 17:11:08 +0100";-ServerWebExchange exchange = MockServerHttpRequest.get("/").header("name", rfc1123val).toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/").header("name", rfc1123val).build();+ServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Object> mono = this.resolver.resolveArgument(this.paramDate, this.bindingContext, exchange);Object result = mono.block();@@ -224,7 +232,8 @@ public void dateConversion() throws Exception {@Testpublic void instantConversion() throws Exception {String rfc1123val = "Thu, 21 Apr 2016 17:11:08 +0100";-ServerWebExchange exchange = MockServerHttpRequest.get("/").header("name", rfc1123val).toExchange();+MockServerHttpRequest request = MockServerHttpRequest.get("/").header("name", rfc1123val).build();+ServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Object> mono = this.resolver.resolveArgument(this.paramInstant, this.bindingContext, exchange);Object result = mono.block();@@ -234,6 +243,7 @@ public void instantConversion() throws Exception {}+@SuppressWarnings("unused")public void params(@RequestHeader(name = "name", defaultValue = "bar") String param1,@RequestHeader("name") String[] param2,
spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java+6 −6
@@ -28,10 +28,10 @@import org.springframework.context.Lifecycle;import org.springframework.core.NamedThreadLocal;import org.springframework.core.io.buffer.DataBufferFactory;+import org.springframework.http.server.reactive.AbstractServerHttpRequest;+import org.springframework.http.server.reactive.AbstractServerHttpResponse;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.http.server.reactive.ServerHttpResponse;-import org.springframework.http.server.reactive.ServletServerHttpRequest;-import org.springframework.http.server.reactive.ServletServerHttpResponse;import org.springframework.lang.Nullable;import org.springframework.util.Assert;import org.springframework.web.reactive.socket.HandshakeInfo;@@ -149,13 +149,13 @@ public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,}private HttpServletRequest getHttpServletRequest(ServerHttpRequest request) {-Assert.isInstanceOf(ServletServerHttpRequest.class, request, "ServletServerHttpRequest required");-return ((ServletServerHttpRequest) request).getServletRequest();+Assert.isInstanceOf(AbstractServerHttpRequest.class, request, "ServletServerHttpRequest required");+return ((AbstractServerHttpRequest) request).getNativeRequest();}private HttpServletResponse getHttpServletResponse(ServerHttpResponse response) {-Assert.isInstanceOf(ServletServerHttpResponse.class, response, "ServletServerHttpResponse required");-return ((ServletServerHttpResponse) response).getServletResponse();+Assert.isInstanceOf(AbstractServerHttpResponse.class, response, "ServletServerHttpResponse required");+return ((AbstractServerHttpResponse) response).getNativeResponse();}private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, @Nullable String protocol) {
spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/TomcatRequestUpgradeStrategy.java+6 −6
@@ -28,10 +28,10 @@import reactor.core.publisher.Mono;import org.springframework.core.io.buffer.DataBufferFactory;+import org.springframework.http.server.reactive.AbstractServerHttpRequest;+import org.springframework.http.server.reactive.AbstractServerHttpResponse;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.http.server.reactive.ServerHttpResponse;-import org.springframework.http.server.reactive.ServletServerHttpRequest;-import org.springframework.http.server.reactive.ServletServerHttpResponse;import org.springframework.lang.Nullable;import org.springframework.util.Assert;import org.springframework.web.reactive.socket.HandshakeInfo;@@ -83,13 +83,13 @@ public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,}private HttpServletRequest getHttpServletRequest(ServerHttpRequest request) {-Assert.isInstanceOf(ServletServerHttpRequest.class, request, "ServletServerHttpRequest required");-return ((ServletServerHttpRequest) request).getServletRequest();+Assert.isInstanceOf(AbstractServerHttpRequest.class, request, "ServletServerHttpRequest required");+return ((AbstractServerHttpRequest) request).getNativeRequest();}private HttpServletResponse getHttpServletResponse(ServerHttpResponse response) {-Assert.isInstanceOf(ServletServerHttpResponse.class, response, "ServletServerHttpResponse required");-return ((ServletServerHttpResponse) response).getServletResponse();+Assert.isInstanceOf(AbstractServerHttpResponse.class, response, "ServletServerHttpResponse required");+return ((AbstractServerHttpResponse) response).getNativeResponse();}private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, @Nullable String protocol) {
spring-webflux/src/test/java/org/springframework/web/reactive/function/server/ResourceHandlerFunctionTests.java+7 −5
@@ -34,10 +34,12 @@import org.springframework.http.codec.HttpMessageWriter;import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;-import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.web.reactive.result.view.ViewResolver;-import static org.junit.Assert.*;+import static org.junit.Assert.assertArrayEquals;+import static org.junit.Assert.assertEquals;+import static org.junit.Assert.assertTrue;/*** @author Arjen Poutsma@@ -71,7 +73,7 @@ public List<ViewResolver> viewResolvers() {@Testpublic void get() throws IOException {-MockServerWebExchange exchange = MockServerHttpRequest.get("http://localhost").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://localhost").build());MockServerHttpResponse mockResponse = exchange.getResponse();ServerRequest request = new DefaultServerRequest(exchange, HandlerStrategies.withDefaults().messageReaders());@@ -107,7 +109,7 @@ public void get() throws IOException {@Testpublic void head() throws IOException {-MockServerWebExchange exchange = MockServerHttpRequest.head("http://localhost").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.head("http://localhost").build());MockServerHttpResponse mockResponse = exchange.getResponse();ServerRequest request = new DefaultServerRequest(exchange, HandlerStrategies.withDefaults().messageReaders());@@ -132,7 +134,7 @@ public void head() throws IOException {@Testpublic void options() {-MockServerWebExchange exchange = MockServerHttpRequest.options("http://localhost").toExchange();+MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.options("http://localhost").build());MockServerHttpResponse mockResponse = exchange.getResponse();ServerRequest request = new DefaultServerRequest(exchange, HandlerStrategies.withDefaults().messageReaders());
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMappingTests.java+26 −20
@@ -36,6 +36,7 @@import org.springframework.http.HttpMethod;import org.springframework.http.MediaType;import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;+import org.springframework.mock.web.test.server.MockServerWebExchange;import org.springframework.stereotype.Controller;import org.springframework.util.ClassUtils;import org.springframework.util.MultiValueMap;@@ -63,6 +64,8 @@import static org.junit.Assert.assertThat;import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.get;import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.method;+import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.post;+import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.put;import static org.springframework.web.bind.annotation.RequestMethod.GET;import static org.springframework.web.bind.annotation.RequestMethod.HEAD;import static org.springframework.web.bind.annotation.RequestMethod.OPTIONS;@@ -95,7 +98,7 @@ public void setup() throws Exception {@Testpublic void getHandlerDirectMatch() throws Exception {Method expected = on(TestController.class).annot(getMapping("/foo").params()).resolveMethod();-ServerWebExchange exchange = get("/foo").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/foo").build());HandlerMethod hm = (HandlerMethod) this.handlerMapping.getHandler(exchange).block();assertEquals(expected, hm.getMethod());@@ -104,7 +107,7 @@ public void getHandlerDirectMatch() throws Exception {@Testpublic void getHandlerGlobMatch() throws Exception {Method expected = on(TestController.class).annot(requestMapping("/ba*").method(GET, HEAD)).resolveMethod();-ServerWebExchange exchange = get("/bar").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/bar").build());HandlerMethod hm = (HandlerMethod) this.handlerMapping.getHandler(exchange).block();assertEquals(expected, hm.getMethod());@@ -113,11 +116,11 @@ public void getHandlerGlobMatch() throws Exception {@Testpublic void getHandlerEmptyPathMatch() throws Exception {Method expected = on(TestController.class).annot(requestMapping("")).resolveMethod();-ServerWebExchange exchange = get("").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("").build());HandlerMethod hm = (HandlerMethod) this.handlerMapping.getHandler(exchange).block();assertEquals(expected, hm.getMethod());-exchange = get("/").toExchange();+exchange = MockServerWebExchange.from(get("/").build());hm = (HandlerMethod) this.handlerMapping.getHandler(exchange).block();assertEquals(expected, hm.getMethod());}@@ -125,7 +128,7 @@ public void getHandlerEmptyPathMatch() throws Exception {@Testpublic void getHandlerBestMatch() throws Exception {Method expected = on(TestController.class).annot(getMapping("/foo").params("p")).resolveMethod();-ServerWebExchange exchange = get("/foo?p=anything").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/foo?p=anything").build());HandlerMethod hm = (HandlerMethod) this.handlerMapping.getHandler(exchange).block();assertEquals(expected, hm.getMethod());@@ -133,7 +136,7 @@ public void getHandlerBestMatch() throws Exception {@Testpublic void getHandlerRequestMethodNotAllowed() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.post("/bar").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(post("/bar").build());Mono<Object> mono = this.handlerMapping.getHandler(exchange);assertError(mono, MethodNotAllowedException.class,@@ -142,7 +145,7 @@ public void getHandlerRequestMethodNotAllowed() throws Exception {@Test // SPR-9603public void getHandlerRequestMethodMatchFalsePositive() throws Exception {-ServerWebExchange exchange = get("/users").accept(MediaType.APPLICATION_XML).toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/users").accept(MediaType.APPLICATION_XML).build());this.handlerMapping.registerHandler(new UserController());Mono<Object> mono = this.handlerMapping.getHandler(exchange);@@ -160,7 +163,8 @@ public void getHandlerMediaTypeNotSupported() throws Exception {@Testpublic void getHandlerTestInvalidContentType() throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.put("/person/1").header("content-type", "bogus").toExchange();+MockServerHttpRequest request = put("/person/1").header("content-type", "bogus").build();+ServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Object> mono = this.handlerMapping.getHandler(exchange);assertError(mono, UnsupportedMediaTypeStatusException.class,@@ -176,7 +180,7 @@ public void getHandlerTestMediaTypeNotAcceptable() throws Exception {@Test // SPR-12854public void getHandlerTestRequestParamMismatch() throws Exception {-ServerWebExchange exchange = get("/params").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/params").build());Mono<Object> mono = this.handlerMapping.getHandler(exchange);assertError(mono, ServerWebInputException.class, ex -> {assertThat(ex.getReason(), containsString("[foo=bar]"));@@ -194,13 +198,13 @@ public void getHandlerHttpOptions() throws Exception {@Testpublic void getHandlerProducibleMediaTypesAttribute() throws Exception {-ServerWebExchange exchange = get("/content").accept(MediaType.APPLICATION_XML).toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/content").accept(MediaType.APPLICATION_XML).build());this.handlerMapping.getHandler(exchange).block();String name = HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;assertEquals(Collections.singleton(MediaType.APPLICATION_XML), exchange.getAttributes().get(name));-exchange = get("/content").accept(MediaType.APPLICATION_JSON).toExchange();+exchange = MockServerWebExchange.from(get("/content").accept(MediaType.APPLICATION_JSON).build());this.handlerMapping.getHandler(exchange).block();assertNull("Negated expression shouldn't be listed as producible type",@@ -210,7 +214,7 @@ public void getHandlerProducibleMediaTypesAttribute() throws Exception {@Test@SuppressWarnings("unchecked")public void handleMatchUriTemplateVariables() throws Exception {-ServerWebExchange exchange = get("/1/2").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/1/2").build());RequestMappingInfo key = paths("/{path1}/{path2}").build();this.handlerMapping.handleMatch(key, handlerMethod, exchange);@@ -227,7 +231,7 @@ public void handleMatchUriTemplateVariables() throws Exception {public void handleMatchUriTemplateVariablesDecode() throws Exception {RequestMappingInfo key = paths("/{group}/{identifier}").build();URI url = URI.create("/group/a%2Fb");-ServerWebExchange exchange = method(HttpMethod.GET, url).toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(method(HttpMethod.GET, url).build());this.handlerMapping.handleMatch(key, handlerMethod, exchange);@@ -243,7 +247,7 @@ public void handleMatchUriTemplateVariablesDecode() throws Exception {@Testpublic void handleMatchBestMatchingPatternAttribute() throws Exception {RequestMappingInfo key = paths("/{path1}/2", "/**").build();-ServerWebExchange exchange = get("/1/2").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/1/2").build());this.handlerMapping.handleMatch(key, handlerMethod, exchange);PathPattern bestMatch = (PathPattern) exchange.getAttributes().get(BEST_MATCHING_PATTERN_ATTRIBUTE);@@ -256,7 +260,7 @@ public void handleMatchBestMatchingPatternAttribute() throws Exception {@Testpublic void handleMatchBestMatchingPatternAttributeNoPatternsDefined() throws Exception {RequestMappingInfo key = paths().build();-ServerWebExchange exchange = get("/1/2").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/1/2").build());this.handlerMapping.handleMatch(key, handlerMethod, exchange);PathPattern bestMatch = (PathPattern) exchange.getAttributes().get(BEST_MATCHING_PATTERN_ATTRIBUTE);@@ -268,7 +272,7 @@ public void handleMatchMatrixVariables() throws Exception {MultiValueMap<String, String> matrixVariables;Map<String, String> uriVariables;-ServerWebExchange exchange = get("/cars;colors=red,blue,green;year=2012").toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get("/cars;colors=red,blue,green;year=2012").build());handleMatch(exchange, "/{cars}");matrixVariables = getMatrixVariables(exchange, "cars");@@ -282,7 +286,8 @@ public void handleMatchMatrixVariables() throws Exception {@Testpublic void handleMatchMatrixVariablesDecoding() throws Exception {-ServerWebExchange exchange = method(HttpMethod.GET, URI.create("/path;mvar=a%2fb")).toExchange();+MockServerHttpRequest request = method(HttpMethod.GET, URI.create("/path;mvar=a%2fb")).build();+ServerWebExchange exchange = MockServerWebExchange.from(request);handleMatch(exchange, "/{filter}");MultiValueMap<String, String> matrixVariables = getMatrixVariables(exchange, "filter");@@ -305,7 +310,8 @@ private <T> void assertError(Mono<Object> mono, final Class<T> exceptionClass, f}private void testHttpMediaTypeNotSupportedException(String url) throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.put(url).contentType(MediaType.APPLICATION_JSON).toExchange();+MockServerHttpRequest request = put(url).contentType(MediaType.APPLICATION_JSON).build();+ServerWebExchange exchange = MockServerWebExchange.from(request);Mono<Object> mono = this.handlerMapping.getHandler(exchange);assertError(mono, UnsupportedMediaTypeStatusException.class, ex ->@@ -315,7 +321,7 @@ private void testHttpMediaTypeNotSupportedException(String url) throws Exception}private void testHttpOptions(String requestURI, Set<HttpMethod> allowedMethods) throws Exception {-ServerWebExchange exchange = MockServerHttpRequest.options(requestURI).toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.options(requestURI).build());HandlerMethod handlerMethod = (HandlerMethod) this.handlerMapping.getHandler(exchange).block();BindingContext bindingContext = new BindingContext();@@ -332,7 +338,7 @@ private void testHttpOptions(String requestURI, Set<HttpMethod> allowedMethods)}private void testMediaTypeNotAcceptable(String url) throws Exception {-ServerWebExchange exchange = get(url).accept(MediaType.APPLICATION_JSON).toExchange();+ServerWebExchange exchange = MockServerWebExchange.from(get(url).accept(MediaType.APPLICATION_JSON).build());Mono<Object> mono = this.handlerMapping.getHandler(exchange);assertError(mono, NotAcceptableStatusException.class, ex ->
src/docs/asciidoc/kotlin.adoc+14 −13
@@ -10,7 +10,7 @@== Introductionhttps://kotlinlang.org[Kotlin] is a statically-typed language targeting the JVM (and other platforms)-which allows writing concise and elegant code while providing a very good+which allows writing concise and elegant code while providing very goodhttps://kotlinlang.org/docs/reference/java-interop.html[interoperability] withexisting libraries written in Java.@@ -75,13 +75,13 @@ val users : Flux<User> = client.get().retrieve().bodyToFlux()----As in Java, `users` in Kotlin is strongly typed, but Kotlin's clever type inference allows-for a shorter syntax.+for shorter syntax.[[null-safety]]== Null-safetyOne of Kotlin's key features is https://kotlinlang.org/docs/reference/null-safety.html[null-safety]-which cleanly deals with `null` values at compile time rather than bumping into the famous+- which cleanly deals with `null` values at compile time rather than bumping into the famous`NullPointerException` at runtime. This makes applications safer through nullabilitydeclarations and expressing "value or no value" semantics without paying the cost of wrappers like `Optional`.(Kotlin allows using functional constructs with nullable values; check out this@@ -302,7 +302,7 @@ https://jira.spring.io/browse/SPR-15064[i18n and nested templates].Kotlin provides similar support and allows the rendering of Kotlin based templates, seehttps://github.com/spring-projects/spring-framework/commit/badde3a479a53e1dd0777dd1bd5b55cb1021cf9e[this commit] for details.-This enables some interesting use cases like writing type-safe templates using+This enables some interesting use cases - like writing type-safe templates usinghttps://github.com/Kotlin/kotlinx.html[kotlinx.html] DSL or simply using Kotlin multiline `String` with interpolation.This can allow one to write Kotlin templates with full autocompletion and@@ -328,7 +328,7 @@ project for more details.[[spring-projects-in-kotlin]]== Spring projects in Kotlin-This section provides a focus on some specific hints and recommendations worth+This section provides focus on some specific hints and recommendations worthknowing when developing Spring projects in Kotlin.=== Final by default@@ -340,11 +340,11 @@ be overridden.Whilst Kotlin's JVM-friendly design is generally frictionless with Spring,this specific Kotlin feature can prevent the application from starting, if this fact is not taken in-consideration. This is because Spring beans are normally proxified with CGLIB+consideration. This is because Spring beans are normally proxied by CGLIB- such as `@Configuration` classes - which need to be inherited at runtime for technical reasons.The workaround was to add an `open` keyword on each class and member-functions of Spring beans proxified with CGLIB such as `@Configuration` classes, which can-quickly become painful and is against Kotlin principle to keep code concise and predictable.+functions of Spring beans proxied by CGLIB such as `@Configuration` classes, which can+quickly become painful and is against the Kotlin principle of keeping code concise and predictable.Fortunately, Kotlin now provides ahttps://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-plugin[`kotlin-spring`]@@ -366,8 +366,9 @@ you will be able to write your Kotlin beans without any additional `open` keywor=== Using immutable class instances for persistence-In Kotlin, it is very convenient and a best practice to declare read-only properties within-the primary constructor, as in the following example:+In Kotlin, it is very convenient and considered best practice to declare+read-only properties within the primary constructor, as in the following+example:[source,kotlin]----@@ -407,9 +408,9 @@ class YourBean([NOTE]====-As of Spring Framework 4.3, classes with a single constructor have its parameters-automatically autowired, that's why there is no need for `@Autowired constructor`-in the example shown above.+As of Spring Framework 4.3, classes with a single constructor have their+parameters automatically autowired, that's why there is no need for an+explicit `@Autowired constructor` in the example shown above.====If one really needs to use field injection, use the `lateinit var` construct,ClientResponse.close().../function/client/ClientResponse.java | 12 ++--.../reactive/function/client/WebClient.java | 64 +++++++++----------src/docs/asciidoc/web/webflux-webclient.adoc | 13 ++--3 files changed, 44 insertions(+), 45 deletions(-)
Release delta 4.2.0.RELEASE → 4.3.20.RELEASE (contains the fix)
spring-tx/src/main/resources/org/springframework/transaction/config/spring-tx-4.2.xsd+247 −0
@@ -0,0 +1,247 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>++<xsd:schema xmlns="http://www.springframework.org/schema/tx"+xmlns:xsd="http://www.w3.org/2001/XMLSchema"+xmlns:beans="http://www.springframework.org/schema/beans"+xmlns:tool="http://www.springframework.org/schema/tool"+targetNamespace="http://www.springframework.org/schema/tx"+elementFormDefault="qualified"+attributeFormDefault="unqualified">++<xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"/>+<xsd:import namespace="http://www.springframework.org/schema/tool" schemaLocation="http://www.springframework.org/schema/tool/spring-tool-4.2.xsd"/>++<xsd:annotation>+<xsd:documentation><![CDATA[+Defines the elements used in the Spring Framework's declarative+transaction management infrastructure.+]]></xsd:documentation>+</xsd:annotation>++<xsd:element name="advice">+<xsd:complexType>+<xsd:annotation>+<xsd:documentation source="java:org.springframework.transaction.interceptor.TransactionInterceptor"><![CDATA[+Defines the transactional semantics of the AOP advice that is to be+executed.++That is, this advice element is where the transactional semantics of+any number of methods are defined (where transactional semantics+includes the propagation settings, the isolation level, the rollback+rules, and suchlike).+]]></xsd:documentation>+<xsd:appinfo>+<tool:annotation>+<tool:exports type="org.springframework.transaction.interceptor.TransactionInterceptor"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+<xsd:complexContent>+<xsd:extension base="beans:identifiedType">+<xsd:sequence>+<xsd:element name="attributes" type="attributesType" minOccurs="0" maxOccurs="1"/>+</xsd:sequence>+<xsd:attribute name="transaction-manager" type="xsd:string" default="transactionManager">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.transaction.PlatformTransactionManager"><![CDATA[+The bean name of the PlatformTransactionManager that is to be used+to drive transactions.++This attribute is not required, and only needs to be specified+explicitly if the bean name of the desired PlatformTransactionManager+is not 'transactionManager'.+]]></xsd:documentation>+<xsd:appinfo>+<tool:annotation kind="ref">+<tool:expected-type type="org.springframework.transaction.PlatformTransactionManager"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+</xsd:attribute>+</xsd:extension>+</xsd:complexContent>+</xsd:complexType>+</xsd:element>++<xsd:element name="annotation-driven">+<xsd:complexType>+<xsd:annotation>+<xsd:documentation source="java:org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"><![CDATA[+Indicates that transaction configuration is defined by Java 5+annotations on bean classes, and that proxies are automatically+to be created for the relevant annotated beans.++The default annotations supported are Spring's @Transactional+and EJB3's @TransactionAttribute (if available).++Transaction semantics such as propagation settings, the isolation level,+the rollback rules, etc are all defined in the annotation metadata.++See org.springframework.transaction.annotation.EnableTransactionManagement Javadoc+for information on code-based alternatives to this XML element.+]]></xsd:documentation>+</xsd:annotation>+<xsd:attribute name="transaction-manager" type="xsd:string" default="transactionManager">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.transaction.PlatformTransactionManager"><![CDATA[+The bean name of the PlatformTransactionManager that is to be used+to drive transactions.++This attribute is not required, and only needs to be specified+explicitly if the bean name of the desired PlatformTransactionManager+is not 'transactionManager'.+]]></xsd:documentation>+<xsd:appinfo>+<tool:annotation kind="ref">+<tool:expected-type type="org.springframework.transaction.PlatformTransactionManager"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="mode" default="proxy">+<xsd:annotation>+<xsd:documentation><![CDATA[+Should annotated beans be proxied using Spring's AOP framework,+or should they rather be weaved with an AspectJ transaction aspect?++AspectJ weaving requires spring-aspects.jar on the classpath,+as well as load-time weaving (or compile-time weaving) enabled.++Note: The weaving-based aspect requires the @Transactional annotation to be+defined on the concrete class. Annotations in interfaces will not work+in that case (they will rather only work with interface-based proxies)!+]]></xsd:documentation>+</xsd:annotation>+<xsd:simpleType>+<xsd:restriction base="xsd:string">+<xsd:enumeration value="proxy"/>+<xsd:enumeration value="aspectj"/>+</xsd:restriction>+</xsd:simpleType>+</xsd:attribute>+<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false">+<xsd:annotation>+<xsd:documentation><![CDATA[+Are class-based (CGLIB) proxies to be created? By default, standard+Java interface-based proxies are created.++Note: Class-based proxies require the @Transactional annotation to be+defined on the concrete class. Annotations in interfaces will not work+in that case (they will rather only work with interface-based proxies)!+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="order" type="xsd:token">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.core.Ordered"><![CDATA[+Controls the ordering of the execution of the transaction advisor+when multiple advice executes at a specific joinpoint.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>+</xsd:element>++<xsd:element name="jta-transaction-manager">+<xsd:annotation>+<xsd:documentation><![CDATA[+Creates a default JtaTransactionManager bean with name "transactionManager",+matching the default bean name expected by the "annotation-driven" tag.+Automatically detects WebLogic and WebSphere: creating a WebLogicJtaTransactionManager+or WebSphereUowTransactionManager, respectively.++For customization needs, consider defining a JtaTransactionManager bean as a regular+Spring bean definition with name "transactionManager", replacing this element.+]]></xsd:documentation>+<xsd:appinfo>+<tool:annotation>+<tool:exports type="org.springframework.transaction.jta.JtaTransactionManager"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+</xsd:element>++<xsd:complexType name="attributesType">+<xsd:sequence>+<xsd:element name="method" minOccurs="1" maxOccurs="unbounded">+<xsd:complexType>+<xsd:attribute name="name" type="xsd:string" use="required">+<xsd:annotation>+<xsd:documentation><![CDATA[+The method name(s) with which the transaction attributes are to be+associated. The wildcard (*) character can be used to associate the+same transaction attribute settings with a number of methods; for+example, 'get*', 'handle*', '*Order', 'on*Event', etc.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="propagation" default="REQUIRED">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.transaction.annotation.Propagation"><![CDATA[+The transaction propagation behavior.+]]></xsd:documentation>+</xsd:annotation>+<xsd:simpleType>+<xsd:restriction base="xsd:string">+<xsd:enumeration value="REQUIRED"/>+<xsd:enumeration value="SUPPORTS"/>+<xsd:enumeration value="MANDATORY"/>+<xsd:enumeration value="REQUIRES_NEW"/>+<xsd:enumeration value="NOT_SUPPORTED"/>+<xsd:enumeration value="NEVER"/>+<xsd:enumeration value="NESTED"/>+</xsd:restriction>+</xsd:simpleType>+</xsd:attribute>+<xsd:attribute name="isolation" default="DEFAULT">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.transaction.annotation.Isolation"><![CDATA[+The transaction isolation level.+]]></xsd:documentation>+</xsd:annotation>+<xsd:simpleType>+<xsd:restriction base="xsd:string">+<xsd:enumeration value="DEFAULT"/>+<xsd:enumeration value="READ_UNCOMMITTED"/>+<xsd:enumeration value="READ_COMMITTED"/>+<xsd:enumeration value="REPEATABLE_READ"/>+<xsd:enumeration value="SERIALIZABLE"/>+</xsd:restriction>+</xsd:simpleType>+</xsd:attribute>+<xsd:attribute name="timeout" type="xsd:int" default="-1">+<xsd:annotation>+<xsd:documentation><![CDATA[+The transaction timeout value (in seconds).+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="read-only" type="xsd:boolean" default="false">+<xsd:annotation>+<xsd:documentation><![CDATA[+Is this transaction read-only?+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="rollback-for" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+The Exception(s) that will trigger rollback; comma-delimited.+For example, 'com.foo.MyBusinessException,ServletException'+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="no-rollback-for" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+The Exception(s) that will *not* trigger rollback; comma-delimited.+For example, 'com.foo.MyBusinessException,ServletException'+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>+</xsd:element>+</xsd:sequence>+</xsd:complexType>++</xsd:schema>compatibility with JDK 9 build 74+)build.gradle | 2 +-1 file changed, 1 insertion(+), 1 deletion(-)
spring-aop/src/main/resources/org/springframework/aop/config/spring-aop-4.2.xsd+399 −0
@@ -0,0 +1,409 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>++<xsd:schema xmlns="http://www.springframework.org/schema/aop"+xmlns:xsd="http://www.w3.org/2001/XMLSchema"+xmlns:tool="http://www.springframework.org/schema/tool"+targetNamespace="http://www.springframework.org/schema/aop"+elementFormDefault="qualified"+attributeFormDefault="unqualified">++<xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"/>+<xsd:import namespace="http://www.springframework.org/schema/tool" schemaLocation="http://www.springframework.org/schema/tool/spring-tool-4.2.xsd"/>++<xsd:annotation>+<xsd:documentation><![CDATA[+Defines the configuration elements for the Spring Framework's AOP support.+]]></xsd:documentation>+</xsd:annotation>++<xsd:element name="config">+<xsd:annotation>+<xsd:documentation><![CDATA[+A section (compartmentalization) of AOP-specific configuration (including+aspects, pointcuts, etc).+]]></xsd:documentation>+</xsd:annotation>+<xsd:complexType>+<xsd:sequence>+<xsd:element name="pointcut" type="pointcutType" minOccurs="0" maxOccurs="unbounded">+<xsd:annotation>+<xsd:documentation><![CDATA[+A named pointcut definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+<xsd:element name="advisor" type="advisorType" minOccurs="0" maxOccurs="unbounded">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.aop.Advisor"><![CDATA[+A named advisor definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+<xsd:element name="aspect" type="aspectType" minOccurs="0" maxOccurs="unbounded">+<xsd:annotation>+<xsd:documentation><![CDATA[+A named aspect definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+</xsd:sequence>+<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false">+<xsd:annotation>+<xsd:documentation><![CDATA[+Are class-based (CGLIB) proxies to be created? By default, standard+Java interface-based proxies are created.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="expose-proxy" type="xsd:boolean" default="false">+<xsd:annotation>+<xsd:documentation><![CDATA[+Indicate that the proxy should be exposed by the AOP framework as a+ThreadLocal for retrieval via the AopContext class. Off by default,+i.e. no guarantees that AopContext access will work.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>+</xsd:element>++<xsd:element name="aspectj-autoproxy">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"><![CDATA[+Enables the use of the @AspectJ style of Spring AOP.++See org.springframework.context.annotation.EnableAspectJAutoProxy Javadoc+for information on code-based alternatives to this XML element.+]]></xsd:documentation>+</xsd:annotation>+<xsd:complexType>+<xsd:sequence>+<xsd:element name="include" type="includeType" minOccurs="0" maxOccurs="unbounded">+<xsd:annotation>+<xsd:documentation><![CDATA[+Indicates that only @AspectJ beans with names matched by the (regex)+pattern will be considered as defining aspects to use for Spring autoproxying.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+</xsd:sequence>+<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false">+<xsd:annotation>+<xsd:documentation><![CDATA[+Are class-based (CGLIB) proxies to be created? By default, standard+Java interface-based proxies are created.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="expose-proxy" type="xsd:boolean" default="false">+<xsd:annotation>+<xsd:documentation><![CDATA[+Indicate that the proxy should be exposed by the AOP framework as a+ThreadLocal for retrieval via the AopContext class. Off by default,+i.e. no guarantees that AopContext access will work.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>+</xsd:element>++<xsd:element name="scoped-proxy">+<xsd:complexType>+<xsd:annotation>+<xsd:documentation source="java:org.springframework.aop.scope.ScopedProxyFactoryBean"><![CDATA[+Marks a bean definition as being a scoped proxy.++A bean marked as such will be exposed via a proxy, with the 'real'+bean instance being retrieved from some other source (such as a+HttpSession) as and when required.+]]></xsd:documentation>+</xsd:annotation>+<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="true">+<xsd:annotation>+<xsd:documentation><![CDATA[+Are class-based (CGLIB) proxies to be created? This is the default; in order to+switch to standard Java interface-based proxies, turn this flag to "false".+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>+</xsd:element>++<xsd:complexType name="aspectType">+<xsd:choice minOccurs="0" maxOccurs="unbounded">+<xsd:element name="pointcut" type="pointcutType">+<xsd:annotation>+<xsd:documentation><![CDATA[+A named pointcut definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+<xsd:element name="declare-parents" type="declareParentsType">+<xsd:annotation>+<xsd:documentation><![CDATA[+Allows this aspect to introduce additional interfaces that the advised+object will transparently implement.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+<xsd:element name="before" type="basicAdviceType">+<xsd:annotation>+<xsd:documentation><![CDATA[+A before advice definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+<xsd:element name="after" type="basicAdviceType">+<xsd:annotation>+<xsd:documentation><![CDATA[+An after advice definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+<xsd:element name="after-returning" type="afterReturningAdviceType">+<xsd:annotation>+<xsd:documentation><![CDATA[+An after-returning advice definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+<xsd:element name="after-throwing" type="afterThrowingAdviceType">+<xsd:annotation>+<xsd:documentation><![CDATA[+An after-throwing advice definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+<xsd:element name="around" type="basicAdviceType">+<xsd:annotation>+<xsd:documentation><![CDATA[+An around advice definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:element>+</xsd:choice>+<xsd:attribute name="id" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+The unique identifier for an aspect.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="ref" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+The name of the (backing) bean that encapsulates the aspect.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="order" type="xsd:token">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.core.Ordered"><![CDATA[+Controls the ordering of the execution of this aspect when multiple+advice executes at a specific joinpoint.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>++<xsd:complexType name="includeType">+<xsd:attribute name="name" type="xsd:string">+<xsd:annotation>+<xsd:documentation source="java:java.util.regex.Pattern"><![CDATA[+The regular expression defining which beans are to be included in the+list of @AspectJ beans; beans with names matched by the pattern will+be included.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>++<xsd:complexType name="pointcutType">+<xsd:annotation>+<xsd:appinfo>+<tool:annotation>+<tool:exports type="org.springframework.aop.Pointcut"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+<xsd:attribute name="id" type="xsd:string" use="required">+<xsd:annotation>+<xsd:documentation><![CDATA[+The unique identifier for a pointcut.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="expression" use="required" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+The pointcut expression.++For example : 'execution(* com.xyz.myapp.service.*.*(..))'+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>++<xsd:complexType name="declareParentsType">+<xsd:attribute name="types-matching" type="xsd:string" use="required">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.aop.aspectj.TypePatternClassFilter"><![CDATA[+The AspectJ type expression that defines what types (classes) the+introduction is restricted to.++An example would be 'org.springframework.beans.ITestBean+'.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="implement-interface" type="xsd:string" use="required">+<xsd:annotation>+<xsd:documentation source="java:java.lang.Class"><![CDATA[+The fully qualified name of the interface that will be introduced.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="default-impl" type="xsd:string">+<xsd:annotation>+<xsd:documentation source="java:java.lang.Class"><![CDATA[+The fully qualified name of the class that will be instantiated to serve+as the default implementation of the introduced interface.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="delegate-ref" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+A reference to the bean that will serve+as the default implementation of the introduced interface.+]]></xsd:documentation>+<xsd:appinfo>+<tool:annotation kind="ref"/>+</xsd:appinfo>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>++<xsd:complexType name="basicAdviceType">+<xsd:attribute name="pointcut" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+The associated pointcut expression.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="pointcut-ref" type="pointcutRefType">+<xsd:annotation>+<xsd:documentation><![CDATA[+The name of an associated pointcut definition.+]]></xsd:documentation>+<xsd:appinfo>+<tool:annotation kind="ref">+<tool:expected-type type="org.springframework.aop.Pointcut"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="method" type="xsd:string" use="required">+<xsd:annotation>+<xsd:documentation><![CDATA[+The name of the method that defines the logic of the advice.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="arg-names" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+The comma-delimited list of advice method argument (parameter) names+that will be matched from pointcut parameters.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>++<xsd:complexType name="afterReturningAdviceType">+<xsd:complexContent>+<xsd:extension base="basicAdviceType">+<xsd:attribute name="returning" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+The name of the method parameter to which the return value must+be passed.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:extension>+</xsd:complexContent>+</xsd:complexType>++<xsd:complexType name="afterThrowingAdviceType">+<xsd:complexContent>+<xsd:extension base="basicAdviceType">+<xsd:attribute name="throwing" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+The name of the method parameter to which the thrown exception must+be passed.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:extension>+</xsd:complexContent>+</xsd:complexType>++<xsd:complexType name="advisorType">+<xsd:annotation>+<xsd:appinfo>+<tool:annotation>+<tool:exports type="org.springframework.aop.Advisor"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+<xsd:attribute name="id" type="xsd:string"/>+<xsd:attribute name="advice-ref" type="xsd:string" use="required">+<xsd:annotation>+<xsd:documentation><![CDATA[+A reference to an advice bean.+]]></xsd:documentation>+<xsd:appinfo>+<tool:annotation kind="ref">+<tool:expected-type type="org.aopalliance.aop.Advice"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="pointcut" type="xsd:string">+<xsd:annotation>+<xsd:documentation><![CDATA[+A pointcut expression.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="pointcut-ref" type="pointcutRefType">+<xsd:annotation>+<xsd:documentation><![CDATA[+A reference to a pointcut definition.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="order" type="xsd:token">+<xsd:annotation>+<xsd:documentation source="java:org.springframework.core.Ordered"><![CDATA[+Controls the ordering of the execution of this advice when multiple+advice executes at a specific joinpoint.+]]></xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:complexType>++<xsd:simpleType name="pointcutRefType">+<xsd:annotation>… diff truncated
spring-oxm/src/main/resources/org/springframework/oxm/config/spring-oxm-4.2.xsd+168 −0
@@ -0,0 +1,168 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<xsd:schema xmlns="http://www.springframework.org/schema/oxm" xmlns:xsd="http://www.w3.org/2001/XMLSchema"+xmlns:beans="http://www.springframework.org/schema/beans"+xmlns:tool="http://www.springframework.org/schema/tool"+targetNamespace="http://www.springframework.org/schema/oxm"+elementFormDefault="qualified"+attributeFormDefault="unqualified">++<xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"/>+<xsd:import namespace="http://www.springframework.org/schema/tool" schemaLocation="http://www.springframework.org/schema/tool/spring-tool-4.2.xsd"/>++<xsd:annotation>+<xsd:documentation>+Defines the elements used in Spring's Object/XML Mapping integration.+</xsd:documentation>+</xsd:annotation>++<xsd:element name="jaxb2-marshaller">+<xsd:complexType>+<xsd:annotation>+<xsd:documentation source="java:org.springframework.oxm.jaxb.Jaxb2Marshaller">+Defines a JAXB2 Marshaller.+</xsd:documentation>+<xsd:appinfo>+<tool:annotation>+<tool:exports type="org.springframework.oxm.jaxb.Jaxb2Marshaller"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+<xsd:complexContent>+<xsd:extension base="beans:identifiedType">+<xsd:sequence>+<xsd:element name="class-to-be-bound" minOccurs="0" maxOccurs="unbounded">+<xsd:complexType>+<xsd:attribute name="name" type="classType" use="required"/>+</xsd:complexType>+</xsd:element>+</xsd:sequence>+<xsd:attribute name="context-path" type="xsd:string">+<xsd:annotation>+<xsd:documentation>The JAXB context path.</xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:extension>+</xsd:complexContent>+</xsd:complexType>+</xsd:element>++<xsd:element name="jibx-marshaller">+<xsd:complexType>+<xsd:annotation>+<xsd:documentation source="java:org.springframework.oxm.jibx.JibxMarshaller">+Defines a JiBX Marshaller.+</xsd:documentation>+<xsd:appinfo>+<tool:annotation>+<tool:exports type="org.springframework.oxm.jibx.JibxMarshaller"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+<xsd:complexContent>+<xsd:extension base="beans:identifiedType">+<xsd:attribute name="target-class" type="classType">+<xsd:annotation>+<xsd:documentation>The target class to be bound with JiBX.</xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="target-package" type="xsd:string">+<xsd:annotation>+<xsd:documentation>The target package for the JiBX binding.</xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="binding-name" type="xsd:string">+<xsd:annotation>+<xsd:documentation>The binding name used by this marshaller.</xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:extension>+</xsd:complexContent>+</xsd:complexType>+</xsd:element>++<xsd:element name="castor-marshaller">+<xsd:complexType>+<xsd:annotation>+<xsd:documentation+source="java:org.springframework.oxm.castor.CastorMarshaller">+Defines a Castor Marshaller.+</xsd:documentation>+<xsd:appinfo>+<tool:annotation>+<tool:exports type="org.springframework.oxm.castor.CastorMarshaller" />+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+<xsd:complexContent>+<xsd:extension base="beans:identifiedType">+<xsd:attribute name="encoding" type="xsd:string">+<xsd:annotation>+<xsd:documentation>The encoding to use for stream reading.</xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="target-class" type="classType">+<xsd:annotation>+<xsd:documentation>The target class to be bound with the Castor marshaller.</xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="target-package" type="xsd:string">+<xsd:annotation>+<xsd:documentation>The target package that contains Castor descriptor classes.</xsd:documentation>+</xsd:annotation>+</xsd:attribute>+<xsd:attribute name="mapping-location" type="xsd:string">+<xsd:annotation>+<xsd:documentation>The path to the Castor mapping file.</xsd:documentation>+</xsd:annotation>+</xsd:attribute>+</xsd:extension>+</xsd:complexContent>+</xsd:complexType>+</xsd:element>++<xsd:element name="xmlbeans-marshaller">+<xsd:complexType>+<xsd:annotation>+<xsd:documentation source="java:org.springframework.oxm.xmlbeans.XmlBeansMarshaller">+Defines a XMLBeans Marshaller.+</xsd:documentation>+<xsd:appinfo>+<tool:annotation>+<tool:exports type="org.springframework.oxm.xmlbeans.XmlBeansMarshaller"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+<xsd:complexContent>+<xsd:extension base="beans:identifiedType">+<xsd:attribute name="options" type="xsd:string">+<xsd:annotation>+<xsd:documentation source="java:org.apache.xmlbeans.XmlOptions">+The bean name of the XmlOptions that is to be used for this marshaller. Typically a+XmlOptionsFactoryBean definition.+</xsd:documentation>+<xsd:appinfo>+<tool:annotation kind="ref">+<tool:expected-type type="org.apache.xmlbeans.XmlOptions"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+</xsd:attribute>+</xsd:extension>+</xsd:complexContent>+</xsd:complexType>+</xsd:element>++<xsd:simpleType name="classType">+<xsd:annotation>+<xsd:documentation source="java:java.lang.Class">A class supported by a marshaller.</xsd:documentation>+<xsd:appinfo>+<tool:annotation kind="direct">+<tool:expected-type type="java.lang.Class"/>+<tool:assignable-to restriction="class-only"/>+</tool:annotation>+</xsd:appinfo>+</xsd:annotation>+<xsd:union memberTypes="xsd:string"/>+</xsd:simpleType>++</xsd:schema>
spring-aop/src/main/resources/META-INF/spring.schemas+2 −1
@@ -5,4 +5,5 @@ http\://www.springframework.org/schema/aop/spring-aop-3.1.xsd=org/springframeworhttp\://www.springframework.org/schema/aop/spring-aop-3.2.xsd=org/springframework/aop/config/spring-aop-3.2.xsdhttp\://www.springframework.org/schema/aop/spring-aop-4.0.xsd=org/springframework/aop/config/spring-aop-4.0.xsdhttp\://www.springframework.org/schema/aop/spring-aop-4.1.xsd=org/springframework/aop/config/spring-aop-4.1.xsd-http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.1.xsd+http\://www.springframework.org/schema/aop/spring-aop-4.2.xsd=org/springframework/aop/config/spring-aop-4.2.xsd+http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.2.xsd
spring-oxm/src/main/resources/META-INF/spring.schemas+2 −1
@@ -3,4 +3,5 @@ http\://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd=org/springframeworhttp\://www.springframework.org/schema/oxm/spring-oxm-3.2.xsd=org/springframework/oxm/config/spring-oxm-3.2.xsdhttp\://www.springframework.org/schema/oxm/spring-oxm-4.0.xsd=org/springframework/oxm/config/spring-oxm-4.0.xsdhttp\://www.springframework.org/schema/oxm/spring-oxm-4.1.xsd=org/springframework/oxm/config/spring-oxm-4.1.xsd-http\://www.springframework.org/schema/oxm/spring-oxm.xsd=org/springframework/oxm/config/spring-oxm-4.1.xsd+http\://www.springframework.org/schema/oxm/spring-oxm-4.2.xsd=org/springframework/oxm/config/spring-oxm-4.2.xsd+http\://www.springframework.org/schema/oxm/spring-oxm.xsd=org/springframework/oxm/config/spring-oxm-4.2.xsd
spring-tx/src/main/resources/META-INF/spring.schemas+2 −1
@@ -5,4 +5,5 @@ http\://www.springframework.org/schema/tx/spring-tx-3.1.xsd=org/springframework/http\://www.springframework.org/schema/tx/spring-tx-3.2.xsd=org/springframework/transaction/config/spring-tx-3.2.xsdhttp\://www.springframework.org/schema/tx/spring-tx-4.0.xsd=org/springframework/transaction/config/spring-tx-4.0.xsdhttp\://www.springframework.org/schema/tx/spring-tx-4.1.xsd=org/springframework/transaction/config/spring-tx-4.1.xsd-http\://www.springframework.org/schema/tx/spring-tx.xsd=org/springframework/transaction/config/spring-tx-4.1.xsd+http\://www.springframework.org/schema/tx/spring-tx-4.2.xsd=org/springframework/transaction/config/spring-tx-4.2.xsd+http\://www.springframework.org/schema/tx/spring-tx.xsd=org/springframework/transaction/config/spring-tx-4.2.xsd
spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java+119 −48
@@ -20,16 +20,21 @@import java.lang.reflect.Method;import java.text.ParseException;import java.util.List;+import java.util.Map;-import com.jayway.jsonpath.InvalidPathException;-import com.jayway.jsonpath.JsonPath;import org.hamcrest.Matcher;import org.springframework.util.Assert;import org.springframework.util.ReflectionUtils;-import static org.hamcrest.MatcherAssert.*;-import static org.springframework.test.util.AssertionErrors.*;+import com.jayway.jsonpath.InvalidPathException;+import com.jayway.jsonpath.JsonPath;++import static org.hamcrest.MatcherAssert.assertThat;+import static org.hamcrest.core.IsInstanceOf.instanceOf;+import static org.springframework.test.util.AssertionErrors.assertEquals;+import static org.springframework.test.util.AssertionErrors.assertTrue;+import static org.springframework.test.util.AssertionErrors.fail;/*** A helper class for applying assertions via JSON path expressions.@@ -39,6 +44,8 @@** @author Rossen Stoyanchev* @author Juergen Hoeller+* @author Craig Andrews+* @author Sam Brannen* @since 3.2*/public class JsonPathExpectationsHelper {@@ -69,12 +76,13 @@ public class JsonPathExpectationsHelper {/**-* Construct a new JsonPathExpectationsHelper.-* @param expression the JsonPath expression-* @param args arguments to parameterize the JSON path expression with+* Construct a new {@code JsonPathExpectationsHelper}.+* @param expression the {@link JsonPath} expression; never {@code null} or empty+* @param args arguments to parameterize the {@code JsonPath} expression, with* formatting specifiers defined in {@link String#format(String, Object...)}*/public JsonPathExpectationsHelper(String expression, Object... args) {+Assert.hasText(expression, "expression must not be null or empty");this.expression = String.format(expression, args);this.jsonPath = (JsonPath) ReflectionUtils.invokeMethod(compileMethod, null, this.expression, emptyFilters);@@ -82,37 +90,25 @@ public JsonPathExpectationsHelper(String expression, Object... args) {/**-* Evaluate the JSON path and assert the resulting value with the given {@code Matcher}.-* @param content the response content-* @param matcher the matcher to assert on the resulting json path+* Evaluate the JSON path expression against the supplied {@code content}+* and assert the resulting value with the given {@code Matcher}.+* @param content the JSON response content+* @param matcher the matcher with which to assert the result*/@SuppressWarnings("unchecked")public <T> void assertValue(String content, Matcher<T> matcher) throws ParseException {T value = (T) evaluateJsonPath(content);-assertThat("JSON path " + this.expression, value, matcher);-}--private Object evaluateJsonPath(String content) throws ParseException {-String message = "No value for JSON path: " + this.expression + ", exception: ";-try {-return this.jsonPath.read(content);-}-catch (InvalidPathException ex) {-throw new AssertionError(message + ex.getMessage());-}-catch (ArrayIndexOutOfBoundsException ex) {-throw new AssertionError(message + ex.getMessage());-}-catch (IndexOutOfBoundsException ex) {-throw new AssertionError(message + ex.getMessage());-}+assertThat("JSON path \"" + this.expression + "\"", value, matcher);}/**-* Apply the JSON path and assert the resulting value.+* Evaluate the JSON path expression against the supplied {@code content}+* and assert that the result is equal to the expected value.+* @param content the JSON response content+* @param expectedValue the expected value*/-public void assertValue(String responseContent, Object expectedValue) throws ParseException {-Object actualValue = evaluateJsonPath(responseContent);+public void assertValue(String content, Object expectedValue) throws ParseException {+Object actualValue = evaluateJsonPath(content);if ((actualValue instanceof List) && !(expectedValue instanceof List)) {@SuppressWarnings("rawtypes")List actualValueList = (List) actualValue;@@ -120,41 +116,90 @@ public void assertValue(String responseContent, Object expectedValue) throws Parfail("No matching value for JSON path \"" + this.expression + "\"");}if (actualValueList.size() != 1) {-fail("Got a list of values " + actualValue + " instead of the value " + expectedValue);+fail("Got a list of values " + actualValue + " instead of the expected single value " + expectedValue);}actualValue = actualValueList.get(0);}else if (actualValue != null && expectedValue != null) {-assertEquals("For JSON path " + this.expression + " type of value",-expectedValue.getClass(), actualValue.getClass());+assertEquals("For JSON path \"" + this.expression + "\", type of value",+expectedValue.getClass().getName(), actualValue.getClass().getName());}-assertEquals("JSON path " + this.expression, expectedValue, actualValue);+assertEquals("JSON path \"" + this.expression + "\"", expectedValue, actualValue);+}++/**+* Evaluate the JSON path expression against the supplied {@code content}+* and assert that the resulting value is a {@link String}.+* @param content the JSON response content+* @since 4.2.1+*/+public void assertValueIsString(String content) throws ParseException {+Object value = assertExistsAndReturn(content);+String reason = "Expected string at JSON path " + this.expression + " but found " + value;+assertThat(reason, value, instanceOf(String.class));+}++/**+* Evaluate the JSON path expression against the supplied {@code content}+* and assert that the resulting value is a {@link Boolean}.+* @param content the JSON response content+* @since 4.2.1+*/+public void assertValueIsBoolean(String content) throws ParseException {+Object value = assertExistsAndReturn(content);+String reason = "Expected boolean at JSON path " + this.expression + " but found " + value;+assertThat(reason, value, instanceOf(Boolean.class));+}++/**+* Evaluate the JSON path expression against the supplied {@code content}+* and assert that the resulting value is a {@link Number}.+* @param content the JSON response content+* @since 4.2.1+*/+public void assertValueIsNumber(String content) throws ParseException {+Object value = assertExistsAndReturn(content);+String reason = "Expected number at JSON path " + this.expression + " but found " + value;+assertThat(reason, value, instanceOf(Number.class));}/**-* Apply the JSON path and assert the resulting value is an array.+* Evaluate the JSON path expression against the supplied {@code content}+* and assert that the resulting value is an array.+* @param content the JSON response content*/-public void assertValueIsArray(String responseContent) throws ParseException {-Object actualValue = evaluateJsonPath(responseContent);-assertTrue("No value for JSON path \"" + this.expression + "\"", actualValue != null);-String reason = "Expected array at JSON path " + this.expression + " but found " + actualValue;-assertTrue(reason, actualValue instanceof List);+public void assertValueIsArray(String content) throws ParseException {+Object value = assertExistsAndReturn(content);+String reason = "Expected array for JSON path \"" + this.expression + "\" but found " + value;+assertTrue(reason, value instanceof List);}/**-* Evaluate the JSON path and assert the resulting content exists.+* Evaluate the JSON path expression against the supplied {@code content}+* and assert that the resulting value is a {@link Map}.+* @param content the JSON response content+* @since 4.2.1+*/+public void assertValueIsMap(String content) throws ParseException {+Object value = assertExistsAndReturn(content);+String reason = "Expected map at JSON path " + this.expression + " but found " + value;+assertThat(reason, value, instanceOf(Map.class));+}++/**+* Evaluate the JSON path expression against the supplied {@code content}+* and assert that the resulting value exists.+* @param content the JSON response content*/public void exists(String content) throws ParseException {-Object value = evaluateJsonPath(content);-String reason = "No value for JSON path " + this.expression;-assertTrue(reason, value != null);-if (List.class.isInstance(value)) {-assertTrue(reason, !((List<?>) value).isEmpty());-}+assertExistsAndReturn(content);}/**-* Evaluate the JSON path and assert it doesn't point to any content.+* Evaluate the JSON path expression against the supplied {@code content}+* and assert that the resulting value is empty (i.e., that a match for+* the JSON path expression does not exist in the supplied content).+* @param content the JSON response content*/public void doesNotExist(String content) throws ParseException {Object value;@@ -173,4 +218,30 @@ public void doesNotExist(String content) throws ParseException {}}+private Object evaluateJsonPath(String content) throws ParseException {+String message = "No value for JSON path \"" + this.expression + "\", exception: ";+try {+return this.jsonPath.read(content);+}+catch (InvalidPathException ex) {+throw new AssertionError(message + ex.getMessage());+}+catch (ArrayIndexOutOfBoundsException ex) {+throw new AssertionError(message + ex.getMessage());+}+catch (IndexOutOfBoundsException ex) {+throw new AssertionError(message + ex.getMessage());+}+}++private Object assertExistsAndReturn(String content) throws ParseException {+Object value = evaluateJsonPath(content);+String reason = "No value for JSON path \"" + this.expression + "\"";+assertTrue(reason, value != null);+if (List.class.isInstance(value)) {+assertTrue(reason, !((List<?>) value).isEmpty());+}+return value;+}+}
spring-web/src/test/java/org/springframework/remoting/caucho/CauchoRemotingTests.java+61 −75
@@ -1,5 +1,5 @@/*-* Copyright 2002-2013 the original author or authors.+* Copyright 2002-2015 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.@@ -16,29 +16,48 @@package org.springframework.remoting.caucho;-import com.caucho.burlap.client.BurlapProxyFactory;-import com.caucho.hessian.client.HessianProxyFactory;-import junit.framework.TestCase;+import java.io.IOException;+import java.net.InetSocketAddress;++import org.junit.Rule;+import org.junit.Test;+import org.junit.rules.ExpectedException;+import org.springframework.aop.framework.ProxyFactory;import org.springframework.remoting.RemoteAccessException;import org.springframework.tests.sample.beans.ITestBean;import org.springframework.tests.sample.beans.TestBean;+import org.springframework.util.SocketUtils;++import com.caucho.burlap.client.BurlapProxyFactory;+import com.caucho.hessian.client.HessianProxyFactory;++import com.sun.net.httpserver.HttpServer;++import static org.junit.Assert.*;/*** @author Juergen Hoeller+* @author Sam Brannen* @since 16.05.2003*/-public class CauchoRemotingTests extends TestCase {+@SuppressWarnings("deprecation")+public class CauchoRemotingTests {++@Rule+public final ExpectedException exception = ExpectedException.none();+-public void testHessianProxyFactoryBeanWithAccessError() throws Exception {+@Test+public void hessianProxyFactoryBeanWithClassInsteadOfInterface() throws Exception {+HessianProxyFactoryBean factory = new HessianProxyFactoryBean();+exception.expect(IllegalArgumentException.class);+factory.setServiceInterface(TestBean.class);+}++@Test+public void hessianProxyFactoryBeanWithAccessError() throws Exception {HessianProxyFactoryBean factory = new HessianProxyFactoryBean();-try {-factory.setServiceInterface(TestBean.class);-fail("Should have thrown IllegalArgumentException");-}-catch (IllegalArgumentException ex) {-// expected-}factory.setServiceInterface(ITestBean.class);factory.setServiceUrl("http://localhosta/testbean");factory.afterPropertiesSet();@@ -47,24 +66,13 @@ public void testHessianProxyFactoryBeanWithAccessError() throws Exception {assertTrue(factory.getObject() instanceof ITestBean);ITestBean bean = (ITestBean) factory.getObject();-try {-bean.setName("test");-fail("Should have thrown RemoteAccessException");-}-catch (RemoteAccessException ex) {-// expected-}+exception.expect(RemoteAccessException.class);+bean.setName("test");}-public void testHessianProxyFactoryBeanWithAuthenticationAndAccessError() throws Exception {+@Test+public void hessianProxyFactoryBeanWithAuthenticationAndAccessError() throws Exception {HessianProxyFactoryBean factory = new HessianProxyFactoryBean();-try {-factory.setServiceInterface(TestBean.class);-fail("Should have thrown IllegalArgumentException");-}-catch (IllegalArgumentException ex) {-// expected-}factory.setServiceInterface(ITestBean.class);factory.setServiceUrl("http://localhosta/testbean");factory.setUsername("test");@@ -76,16 +84,12 @@ public void testHessianProxyFactoryBeanWithAuthenticationAndAccessError() throwsassertTrue(factory.getObject() instanceof ITestBean);ITestBean bean = (ITestBean) factory.getObject();-try {-bean.setName("test");-fail("Should have thrown RemoteAccessException");-}-catch (RemoteAccessException ex) {-// expected-}+exception.expect(RemoteAccessException.class);+bean.setName("test");}-public void testHessianProxyFactoryBeanWithCustomProxyFactory() throws Exception {+@Test+public void hessianProxyFactoryBeanWithCustomProxyFactory() throws Exception {TestHessianProxyFactory proxyFactory = new TestHessianProxyFactory();HessianProxyFactoryBean factory = new HessianProxyFactoryBean();factory.setServiceInterface(ITestBean.class);@@ -103,16 +107,12 @@ public void testHessianProxyFactoryBeanWithCustomProxyFactory() throws ExceptionassertEquals(proxyFactory.password, "bean");assertTrue(proxyFactory.overloadEnabled);-try {-bean.setName("test");-fail("Should have thrown RemoteAccessException");-}-catch (RemoteAccessException ex) {-// expected-}+exception.expect(RemoteAccessException.class);+bean.setName("test");}-public void testBurlapProxyFactoryBeanWithAccessError() throws Exception {+@Test+public void burlapProxyFactoryBeanWithAccessError() throws Exception {BurlapProxyFactoryBean factory = new BurlapProxyFactoryBean();factory.setServiceInterface(ITestBean.class);factory.setServiceUrl("http://localhosta/testbean");@@ -122,16 +122,12 @@ public void testBurlapProxyFactoryBeanWithAccessError() throws Exception {assertTrue(factory.getObject() instanceof ITestBean);ITestBean bean = (ITestBean) factory.getObject();-try {-bean.setName("test");-fail("Should have thrown RemoteAccessException");-}-catch (RemoteAccessException ex) {-// expected-}+exception.expect(RemoteAccessException.class);+bean.setName("test");}-public void testBurlapProxyFactoryBeanWithAuthenticationAndAccessError() throws Exception {+@Test+public void burlapProxyFactoryBeanWithAuthenticationAndAccessError() throws Exception {BurlapProxyFactoryBean factory = new BurlapProxyFactoryBean();factory.setServiceInterface(ITestBean.class);factory.setServiceUrl("http://localhosta/testbean");@@ -144,16 +140,12 @@ public void testBurlapProxyFactoryBeanWithAuthenticationAndAccessError() throwsassertTrue(factory.getObject() instanceof ITestBean);ITestBean bean = (ITestBean) factory.getObject();-try {-bean.setName("test");-fail("Should have thrown RemoteAccessException");-}-catch (RemoteAccessException ex) {-// expected-}+exception.expect(RemoteAccessException.class);+bean.setName("test");}-public void testBurlapProxyFactoryBeanWithCustomProxyFactory() throws Exception {+@Test+public void burlapProxyFactoryBeanWithCustomProxyFactory() throws Exception {TestBurlapProxyFactory proxyFactory = new TestBurlapProxyFactory();BurlapProxyFactoryBean factory = new BurlapProxyFactoryBean();factory.setServiceInterface(ITestBean.class);@@ -172,32 +164,27 @@ public void testBurlapProxyFactoryBeanWithCustomProxyFactory() throws ExceptionassertEquals(proxyFactory.password, "bean");assertTrue(proxyFactory.overloadEnabled);-try {-bean.setName("test");-fail("Should have thrown RemoteAccessException");-}-catch (RemoteAccessException ex) {-// expected-}+exception.expect(RemoteAccessException.class);+bean.setName("test");}-/** Using the JDK 1.6 HttpServer breaks when running multiple test methods-public void testSimpleHessianServiceExporter() throws IOException {-if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16) {-return;-}+@Test+public void simpleHessianServiceExporter() throws IOException {+final int port = SocketUtils.findAvailableTcpPort();+TestBean tb = new TestBean("tb");SimpleHessianServiceExporter exporter = new SimpleHessianServiceExporter();exporter.setService(tb);exporter.setServiceInterface(ITestBean.class);exporter.setDebug(true);exporter.prepare();-HttpServer server = HttpServer.create(new InetSocketAddress(8889), -1);++HttpServer server = HttpServer.create(new InetSocketAddress(port), -1);server.createContext("/hessian", exporter);server.start();try {HessianClientInterceptor client = new HessianClientInterceptor();-client.setServiceUrl("http://localhost:8889/hessian");+client.setServiceUrl("http://localhost:" + port + "/hessian");client.setServiceInterface(ITestBean.class);//client.setHessian2(true);client.prepare();@@ -210,7 +197,6 @@ public void testSimpleHessianServiceExporter() throws IOException {server.stop(Integer.MAX_VALUE);}}-*/private static class TestHessianProxyFactory extends HessianProxyFactory {CommonsPool2TargetSource#maxWait.../springframework/aop/target/CommonsPool2TargetSource.java | 5 +++--1 file changed, 3 insertions(+), 2 deletions(-)
spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java+21 −34
@@ -19,13 +19,13 @@import java.io.FileNotFoundException;import java.io.IOException;import java.util.ArrayList;-import java.util.Arrays;import java.util.List;import org.junit.Ignore;import org.junit.Test;import org.springframework.core.io.Resource;+import org.springframework.util.StringUtils;import static org.junit.Assert.*;@@ -42,19 +42,17 @@ public class PathMatchingResourcePatternResolverTests {private static final String[] CLASSES_IN_CORE_IO_SUPPORT =new String[] {"EncodedResource.class", "LocalizedResourceHelper.class",-"PathMatchingResourcePatternResolver.class",-"PropertiesLoaderSupport.class", "PropertiesLoaderUtils.class",-"ResourceArrayPropertyEditor.class",-"ResourcePatternResolver.class", "ResourcePatternUtils.class"};+"PathMatchingResourcePatternResolver.class", "PropertiesLoaderSupport.class",+"PropertiesLoaderUtils.class", "ResourceArrayPropertyEditor.class",+"ResourcePatternResolver.class", "ResourcePatternUtils.class"};private static final String[] TEST_CLASSES_IN_CORE_IO_SUPPORT =new String[] {"PathMatchingResourcePatternResolverTests.class"};private static final String[] CLASSES_IN_COMMONSLOGGING =new String[] {"Log.class", "LogConfigurationException.class", "LogFactory.class",-"LogFactory$1.class", "LogFactory$2.class", "LogFactory$3.class",-"LogFactory$4.class", "LogFactory$5.class", "LogFactory$6.class",-"LogSource.class"};+"LogFactory$1.class", "LogFactory$2.class", "LogFactory$3.class", "LogFactory$4.class",+"LogFactory$5.class", "LogFactory$6.class", "LogSource.class"};private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();@@ -75,19 +73,17 @@ public void testSingleResourceOnFileSystem() throws IOException {Resource[] resources =resolver.getResources("org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.class");assertEquals(1, resources.length);-assertProtocolAndFilename(resources[0], "file", "PathMatchingResourcePatternResolverTests.class");+assertProtocolAndFilenames(resources, "file", "PathMatchingResourcePatternResolverTests.class");}@Testpublic void testSingleResourceInJar() throws IOException {Resource[] resources = resolver.getResources("java/net/URL.class");assertEquals(1, resources.length);-@SuppressWarnings("deprecation")-String expectedProtocol = (org.springframework.core.JdkVersion.getMajorJavaVersion() < org.springframework.core.JdkVersion.JAVA_19 ? "jar" : "jrt");-assertProtocolAndFilename(resources[0], expectedProtocol, "URL.class");+assertProtocolAndFilenames(resources, "jar", "URL.class");}-@Ignore // passes under eclipse, fails under ant+@Ignore // passes under Eclipse, fails under Ant@Testpublic void testClasspathStarWithPatternOnFileSystem() throws IOException {Resource[] resources = resolver.getResources("classpath*:org/springframework/core/io/sup*/*.class");@@ -100,7 +96,8 @@ public void testClasspathStarWithPatternOnFileSystem() throws IOException {}}resources = noCloverResources.toArray(new Resource[noCloverResources.size()]);-assertProtocolAndFilenames(resources, "file", CLASSES_IN_CORE_IO_SUPPORT, TEST_CLASSES_IN_CORE_IO_SUPPORT);+assertProtocolAndFilenames(resources, "file",+StringUtils.concatenateStringArrays(CLASSES_IN_CORE_IO_SUPPORT, TEST_CLASSES_IN_CORE_IO_SUPPORT));}@Test@@ -128,19 +125,7 @@ public void testRootPatternRetrievalInJarFiles() throws IOException {}-private void assertProtocolAndFilename(Resource resource, String urlProtocol, String fileName) throws IOException {-assertProtocolAndFilenames(new Resource[] {resource}, urlProtocol, new String[] {fileName});-}--private void assertProtocolAndFilenames(-Resource[] resources, String urlProtocol, String[] fileNames1, String[] fileNames2) throws IOException {--List<String> fileNames = new ArrayList<String>(Arrays.asList(fileNames1));-fileNames.addAll(Arrays.asList(fileNames2));-assertProtocolAndFilenames(resources, urlProtocol, fileNames.toArray(new String[fileNames.size()]));-}--private void assertProtocolAndFilenames(Resource[] resources, String urlProtocol, String[] fileNames)+private void assertProtocolAndFilenames(Resource[] resources, String protocol, String... filenames)throws IOException {// Uncomment the following if you encounter problems with matching against the file system@@ -161,20 +146,22 @@ private void assertProtocolAndFilenames(Resource[] resources, String urlProtocol// System.out.println(resources[i]);// }-assertEquals("Correct number of files found", fileNames.length, resources.length);+assertEquals("Correct number of files found", filenames.length, resources.length);for (Resource resource : resources) {-assertEquals(urlProtocol, resource.getURL().getProtocol());-assertFilenameIn(resource, fileNames);+String actualProtocol = resource.getURL().getProtocol();+// resources from rt.jar get retrieved as jrt images on JDK 9, so let's simply accept that as a match too+assertTrue(actualProtocol.equals(protocol) || ("jar".equals(protocol) && "jrt".equals(actualProtocol)));+assertFilenameIn(resource, filenames);}}-private void assertFilenameIn(Resource resource, String[] fileNames) {-for (String fileName : fileNames) {-if (resource.getFilename().endsWith(fileName)) {+private void assertFilenameIn(Resource resource, String... filenames) {+for (String filename : filenames) {+if (resource.getFilename().endsWith(filename)) {return;}}-fail("resource [" + resource + "] does not have a filename that matches and of the names in 'fileNames'");+fail(resource + " does not have a filename that matches any of the specified names");}}
spring-websocket/src/main/java/org/springframework/web/socket/server/standard/WebSphereRequestUpgradeStrategy.java+95 −0
@@ -0,0 +1,95 @@+/*+* Copyright 2002-2014 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.+* You may obtain a copy of the License at+*+* http://www.apache.org/licenses/LICENSE-2.0+*+* Unless required by applicable law or agreed to in writing, software+* distributed under the License is distributed on an "AS IS" BASIS,+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+* See the License for the specific language governing permissions and+* limitations under the License.+*/++package org.springframework.web.socket.server.standard;++import java.lang.reflect.Method;+import java.util.Collections;+import java.util.List;+import java.util.Map;+import javax.servlet.http.HttpServletRequest;+import javax.servlet.http.HttpServletResponse;+import javax.websocket.Endpoint;+import javax.websocket.Extension;+import javax.websocket.server.ServerContainer;+import javax.websocket.server.ServerEndpointConfig;++import org.springframework.http.server.ServerHttpRequest;+import org.springframework.http.server.ServerHttpResponse;+import org.springframework.web.socket.server.HandshakeFailureException;++/**+* WebSphere support for upgrading an {@link HttpServletRequest} during a+* WebSocket handshake. To modify properties of the underlying+* {@link javax.websocket.server.ServerContainer} you can use+* {@link ServletServerContainerFactoryBean} in XML configuration or, when using+* Java configuration, access the container instance through the+* "javax.websocket.server.ServerContainer" ServletContext attribute.+*+* <p>Tested with WAS Liberty beta (August 2015) for the upcoming 8.5.5.7 release.+*+* @author Rossen Stoyanchev+* @since 4.2.1+*/+public class WebSphereRequestUpgradeStrategy extends AbstractStandardUpgradeStrategy {++private final static Method upgradeMethod;++static {+ClassLoader loader = WebSphereRequestUpgradeStrategy.class.getClassLoader();+try {+Class<?> type = loader.loadClass("com.ibm.websphere.wsoc.WsWsocServerContainer");+upgradeMethod = type.getMethod("doUpgrade", HttpServletRequest.class,+HttpServletResponse.class, ServerEndpointConfig.class, Map.class);+}+catch (Exception ex) {+throw new IllegalStateException("No compatible WebSphere version found", ex);+}+}+++@Override+public String[] getSupportedVersions() {+return new String[] {"13"};+}++@Override+public void upgradeInternal(ServerHttpRequest httpRequest, ServerHttpResponse httpResponse,+String selectedProtocol, List<Extension> selectedExtensions, Endpoint endpoint)+throws HandshakeFailureException {++HttpServletRequest request = getHttpServletRequest(httpRequest);+HttpServletResponse response = getHttpServletResponse(httpResponse);++StringBuffer requestUrl = request.getRequestURL();+String path = request.getRequestURI(); // shouldn't matter+Map<String, String> pathParams = Collections.<String, String> emptyMap();++ServerEndpointRegistration endpointConfig = new ServerEndpointRegistration(path, endpoint);+endpointConfig.setSubprotocols(Collections.singletonList(selectedProtocol));+endpointConfig.setExtensions(selectedExtensions);++try {+ServerContainer container = getContainer(request);+upgradeMethod.invoke(container, request, response, endpointConfig, pathParams);+}+catch (Exception ex) {+throw new HandshakeFailureException(+"Servlet request failed to upgrade to WebSocket, uri=" + requestUrl, ex);+}+}++}
spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheTests.java+15 −2
@@ -16,9 +16,11 @@package org.springframework.cache.jcache;+import javax.annotation.Resource;import javax.cache.CacheManager;import javax.cache.Caching;import javax.cache.configuration.MutableConfiguration;+import javax.cache.spi.CachingProvider;import org.junit.After;import org.junit.Ignore;@@ -48,7 +50,10 @@ public class JCacheEhCacheTests extends AbstractAnnotationTests {@Overrideprotected ConfigurableApplicationContext getApplicationContext() {-ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(EnableCachingConfig.class);+AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();+context.getBeanFactory().registerSingleton("cachingProvider", getCachingProvider());+context.register(EnableCachingConfig.class);+context.refresh();jCacheManager = context.getBean("jCacheManager", CacheManager.class);return context;}@@ -68,10 +73,18 @@ public void testCustomCacheManager() {}+protected CachingProvider getCachingProvider() {+return Caching.getCachingProvider();+}++@Configuration@EnableCachingstatic class EnableCachingConfig extends CachingConfigurerSupport {+@Resource+CachingProvider cachingProvider;+@Override@Beanpublic org.springframework.cache.CacheManager cacheManager() {@@ -80,7 +93,7 @@ public org.springframework.cache.CacheManager cacheManager() {@Beanpublic CacheManager jCacheManager() {-CacheManager cacheManager = Caching.getCachingProvider().getCacheManager();+CacheManager cacheManager = this.cachingProvider.getCacheManager();MutableConfiguration<Object, Object> mutableConfiguration = new MutableConfiguration<Object, Object>();mutableConfiguration.setStoreByValue(false); // otherwise value has to be SerializablecacheManager.createCache("testCache", mutableConfiguration);
spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java+11 −17
@@ -576,29 +576,22 @@ public boolean supports(Class<?> clazz) {}@Override-@SuppressWarnings("deprecation")public boolean supports(Type genericType) {if (genericType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericType;if (JAXBElement.class == parameterizedType.getRawType() &¶meterizedType.getActualTypeArguments().length == 1) {-boolean isJdk6 = (org.springframework.core.JdkVersion.getMajorJavaVersion() <= org.springframework.core.JdkVersion.JAVA_16);-boolean isJdk7 = (org.springframework.core.JdkVersion.getMajorJavaVersion() >= org.springframework.core.JdkVersion.JAVA_17);Type typeArgument = parameterizedType.getActualTypeArguments()[0];if (typeArgument instanceof Class) {Class<?> classArgument = (Class<?>) typeArgument;-if (isJdk7 && classArgument.isArray()) {-return (classArgument.getComponentType() == Byte.TYPE);-}-else {-return (isPrimitiveWrapper(classArgument) || isStandardClass(classArgument) ||-supportsInternal(classArgument, false));-}+return (((classArgument.isArray() && Byte.TYPE == classArgument.getComponentType())) ||+isPrimitiveWrapper(classArgument) || isStandardClass(classArgument) ||+supportsInternal(classArgument, false));}-else if (isJdk6 && typeArgument instanceof GenericArrayType) {-// see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5041784+else if (typeArgument instanceof GenericArrayType) {+// Only on JDK 6 - see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5041784GenericArrayType arrayType = (GenericArrayType) typeArgument;-return (arrayType.getGenericComponentType() == Byte.TYPE);+return (Byte.TYPE == arrayType.getGenericComponentType());}}}@@ -634,13 +627,13 @@ else if (!ObjectUtils.isEmpty(this.classesToBeBound)) {* Compare section 8.5.1 of the JAXB2 spec.*/private boolean isPrimitiveWrapper(Class<?> clazz) {-return Boolean.class == clazz ||+return (Boolean.class == clazz ||Byte.class == clazz ||Short.class == clazz ||Integer.class == clazz ||Long.class == clazz ||Float.class == clazz ||-Double.class == clazz;+Double.class == clazz);}/**@@ -648,7 +641,7 @@ private boolean isPrimitiveWrapper(Class<?> clazz) {* Compare section 8.5.2 of the JAXB2 spec.*/private boolean isStandardClass(Class<?> clazz) {-return String.class == clazz ||+return (String.class == clazz ||BigInteger.class.isAssignableFrom(clazz) ||BigDecimal.class.isAssignableFrom(clazz) ||Calendar.class.isAssignableFrom(clazz) ||@@ -661,10 +654,11 @@ private boolean isStandardClass(Class<?> clazz) {DataHandler.class == clazz ||// Source and subclasses should be supported according to the JAXB2 spec, but aren't in the RI// Source.class.isAssignableFrom(clazz) ||-UUID.class == clazz;+UUID.class == clazz);}+// Marshalling@OverrideconversionHint arguments.../converter/AbstractMessageConverter.java | 34 ++--------.../converter/CompositeMessageConverter.java | 54 +++++++++++++---.../converter/SmartMessageConverter.java | 62 +++++++++++++++++++.../core/AbstractMessageSendingTemplate.java | 6 +-.../support/PayloadArgumentResolver.java | 6 +-5 files changed, 117 insertions(+), 45 deletions(-)create mode 100644 spring-messaging/src/main/java/org/springframework/messaging/converter/SmartMessageConverter.java
spring-messaging/src/main/java/org/springframework/messaging/converter/SmartMessageConverter.java+62 −0
@@ -0,0 +1,62 @@+/*+* Copyright 2002-2015 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.+* You may obtain a copy of the License at+*+* http://www.apache.org/licenses/LICENSE-2.0+*+* Unless required by applicable law or agreed to in writing, software+* distributed under the License is distributed on an "AS IS" BASIS,+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+* See the License for the specific language governing permissions and+* limitations under the License.+*/++package org.springframework.messaging.converter;++import org.springframework.messaging.Message;+import org.springframework.messaging.MessageHeaders;++/**+* An extended {@link MessageConverter} SPI with conversion hint support.+*+* <p>In case of a conversion hint being provided, the framework will call+* these extended methods if a converter implements this interface, instead+* of calling the regular {@code fromMessage} / {@code toMessage} variants.+*+* @author Juergen Hoeller+* @since 4.2.1+*/+public interface SmartMessageConverter extends MessageConverter {++/**+* A variant of {@link #fromMessage(Message, Class)} which takes an extra+* conversion context as an argument, allowing to take e.g. annotations+* on a payload parameter into account.+* @param message the input message+* @param targetClass the target class for the conversion+* @param conversionHint an extra object passed to the {@link MessageConverter},+* e.g. the associated {@code MethodParameter} (may be {@code null}}+* @return the result of the conversion, or {@code null} if the converter cannot+* perform the conversion+* @see #fromMessage(Message, Class)+*/+Object fromMessage(Message<?> message, Class<?> targetClass, Object conversionHint);++/**+* A variant of {@link #toMessage(Object, MessageHeaders)} which takes an extra+* conversion context as an argument, allowing to take e.g. annotations+* on a return type into account.+* @param payload the Object to convert+* @param headers optional headers for the message (may be {@code null})+* @param conversionHint an extra object passed to the {@link MessageConverter},+* e.g. the associated {@code MethodParameter} (may be {@code null}}+* @return the new message, or {@code null} if the converter does not support the+* Object type or the target media type+* @see #toMessage(Object, MessageHeaders)+*/+Message<?> toMessage(Object payload, MessageHeaders headers, Object conversionHint);++}
spring-beans/src/test/java/org/springframework/beans/factory/serviceloader/ServiceLoaderTests.java+4 −8
@@ -1,5 +1,5 @@/*-* Copyright 2002-2007 the original author or authors.+* Copyright 2002-2015 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.@@ -24,7 +24,6 @@import org.springframework.beans.factory.support.DefaultListableBeanFactory;import org.springframework.beans.factory.support.RootBeanDefinition;-import org.springframework.core.JdkVersion;import static org.junit.Assert.*;@@ -36,8 +35,7 @@ public class ServiceLoaderTests {@Testpublic void testServiceLoaderFactoryBean() {-if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16 ||-!ServiceLoader.load(DocumentBuilderFactory.class).iterator().hasNext()){+if (!ServiceLoader.load(DocumentBuilderFactory.class).iterator().hasNext()){return;}@@ -51,8 +49,7 @@ public void testServiceLoaderFactoryBean() {@Testpublic void testServiceFactoryBean() {-if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16 ||-!ServiceLoader.load(DocumentBuilderFactory.class).iterator().hasNext()){+if (!ServiceLoader.load(DocumentBuilderFactory.class).iterator().hasNext()){return;}@@ -65,8 +62,7 @@ public void testServiceFactoryBean() {@Testpublic void testServiceListFactoryBean() {-if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16 ||-!ServiceLoader.load(DocumentBuilderFactory.class).iterator().hasNext()){+if (!ServiceLoader.load(DocumentBuilderFactory.class).iterator().hasNext()){return;}
spring-web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java+43 −23
@@ -1,5 +1,5 @@/*-* Copyright 2002-2014 the original author or authors.+* Copyright 2002-2015 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.@@ -44,33 +44,49 @@import org.springframework.util.LinkedMultiValueMap;import org.springframework.util.MultiValueMap;-import static org.junit.Assert.*;-import static org.mockito.BDDMockito.*;+import static org.junit.Assert.assertEquals;+import static org.junit.Assert.assertFalse;+import static org.junit.Assert.assertNotNull;+import static org.junit.Assert.assertNull;+import static org.junit.Assert.assertTrue;+import static org.mockito.BDDMockito.never;+import static org.mockito.BDDMockito.verify;/*** @author Arjen Poutsma+* @author Rossen Stoyanchev*/public class FormHttpMessageConverterTests {+public static final Charset UTF_8 = Charset.forName("UTF-8");++private FormHttpMessageConverter converter;+@Beforepublic void setUp() {-converter = new AllEncompassingFormHttpMessageConverter();+this.converter = new AllEncompassingFormHttpMessageConverter();}+@Testpublic void canRead() {-assertTrue(converter.canRead(MultiValueMap.class, new MediaType("application", "x-www-form-urlencoded")));-assertFalse(converter.canRead(MultiValueMap.class, new MediaType("multipart", "form-data")));+assertTrue(this.converter.canRead(MultiValueMap.class,+new MediaType("application", "x-www-form-urlencoded")));+assertFalse(this.converter.canRead(MultiValueMap.class,+new MediaType("multipart", "form-data")));}@Testpublic void canWrite() {-assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("application", "x-www-form-urlencoded")));-assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("multipart", "form-data")));-assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("multipart", "form-data", Charset.forName("UTF-8"))));-assertTrue(converter.canWrite(MultiValueMap.class, MediaType.ALL));+assertTrue(this.converter.canWrite(MultiValueMap.class,+new MediaType("application", "x-www-form-urlencoded")));+assertTrue(this.converter.canWrite(MultiValueMap.class,+new MediaType("multipart", "form-data")));+assertTrue(this.converter.canWrite(MultiValueMap.class,+new MediaType("multipart", "form-data", Charset.forName("UTF-8"))));+assertTrue(this.converter.canWrite(MultiValueMap.class, MediaType.ALL));}@Test@@ -79,7 +95,7 @@ public void readForm() throws Exception {Charset iso88591 = Charset.forName("ISO-8859-1");MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(iso88591));inputMessage.getHeaders().setContentType(new MediaType("application", "x-www-form-urlencoded", iso88591));-MultiValueMap<String, String> result = converter.read(null, inputMessage);+MultiValueMap<String, String> result = this.converter.read(null, inputMessage);assertEquals("Invalid result", 3, result.size());assertEquals("Invalid result", "value 1", result.getFirst("name 1"));@@ -98,9 +114,10 @@ public void writeForm() throws IOException {body.add("name 2", "value 2+2");body.add("name 3", null);MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();-converter.write(body, MediaType.APPLICATION_FORM_URLENCODED, outputMessage);+this.converter.write(body, MediaType.APPLICATION_FORM_URLENCODED, outputMessage);+assertEquals("Invalid result", "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3",-outputMessage.getBodyAsString(Charset.forName("UTF-8")));+outputMessage.getBodyAsString(UTF_8));assertEquals("Invalid content-type", new MediaType("application", "x-www-form-urlencoded"),outputMessage.getHeaders().getContentType());assertEquals("Invalid content-length", outputMessage.getBodyAsBytes().length,@@ -119,7 +136,6 @@ public void writeMultipart() throws Exception {parts.add("logo", logo);// SPR-12108-Resource utf8 = new ClassPathResource("/org/springframework/http/converter/logo.jpg") {@Overridepublic String getFilename() {@@ -135,8 +151,8 @@ public String getFilename() {parts.add("xml", entity);MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();-converter.setMultipartCharset(Charset.forName("UTF-8"));-converter.write(parts, new MediaType("multipart", "form-data", Charset.forName("UTF-8")), outputMessage);+this.converter.setMultipartCharset(UTF_8);+this.converter.write(parts, new MediaType("multipart", "form-data", UTF_8), outputMessage);final MediaType contentType = outputMessage.getHeaders().getContentType();assertNotNull("No boundary found", contentType.getParameter("boundary"));@@ -144,7 +160,8 @@ public String getFilename() {// see if Commons FileUpload can read what we wroteFileItemFactory fileItemFactory = new DiskFileItemFactory();FileUpload fileUpload = new FileUpload(fileItemFactory);-List<FileItem> items = fileUpload.parseRequest(new MockHttpOutputMessageRequestContext(outputMessage));+RequestContext requestContext = new MockHttpOutputMessageRequestContext(outputMessage);+List<FileItem> items = fileUpload.parseRequest(requestContext);assertEquals(6, items.size());FileItem item = items.get(0);assertTrue(item.isFormField());@@ -181,35 +198,38 @@ public String getFilename() {verify(outputMessage.getBody(), never()).close();}+private static class MockHttpOutputMessageRequestContext implements RequestContext {private final MockHttpOutputMessage outputMessage;+private MockHttpOutputMessageRequestContext(MockHttpOutputMessage outputMessage) {this.outputMessage = outputMessage;}+@Overridepublic String getCharacterEncoding() {-MediaType contentType = outputMessage.getHeaders().getContentType();-return contentType != null && contentType.getCharSet() != null ? contentType.getCharSet().name() : null;+MediaType type = this.outputMessage.getHeaders().getContentType();+return (type != null && type.getCharSet() != null ? type.getCharSet().name() : null);}@Overridepublic String getContentType() {-MediaType contentType = outputMessage.getHeaders().getContentType();-return contentType != null ? contentType.toString() : null;+MediaType type = this.outputMessage.getHeaders().getContentType();+return (type != null ? type.toString() : null);}@Override@Deprecatedpublic int getContentLength() {-return outputMessage.getBodyAsBytes().length;+return this.outputMessage.getBodyAsBytes().length;}@Overridepublic InputStream getInputStream() throws IOException {-return new ByteArrayInputStream(outputMessage.getBodyAsBytes());+return new ByteArrayInputStream(this.outputMessage.getBodyAsBytes());}}AllEncompassingFormHttpMessageConverter...lEncompassingFormHttpMessageConverter.java | 9 +--.../FormHttpMessageConverterTests.java | 56 +++++++++++++++++++2 files changed, 61 insertions(+), 4 deletions(-)
References
- ADVISORYhttps://nvd.nist.gov/vuln/detail/CVE-2018-15756
- WEBhttps://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html
- WEBhttps://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html
- WEBhttps://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html
- WEBhttps://www.oracle.com/security-alerts/cpuoct2021.html
- WEBhttps://www.oracle.com/security-alerts/cpujul2020.html
- WEBhttps://www.oracle.com/security-alerts/cpujan2021.html
- WEBhttps://www.oracle.com/security-alerts/cpujan2020.html
- WEBhttps://www.oracle.com/security-alerts/cpuapr2020.html
- WEBhttps://www.oracle.com//security-alerts/cpujul2021.html
- WEBhttps://pivotal.io/security/cve-2018-15756
- WEBhttps://lists.debian.org/debian-lts-announce/2021/04/msg00022.html