Spring Framework 5.0 introduced a regression in ASM-based annotation
processing. Specifically, nested annotations were no longer supported,
and component scanning resulted in an exception if a candidate
component was annotated with an annotation that contained nested
annotations.
This commit fixes this regression by introducing special handling in
AnnotationTypeMapping that supports extracting values from objects of
type TypeMappedAnnotation when necessary.
Closes gh-24375
This is a follow-up on the earlier commit
28a95e89f3 eliminating windowUntil
entirely which generates a BubblingException wrapper. This also keeps
the chain a little simpler.
See gh-24355
Spring Framework provides two implementations of the
CommandLinePropertySource API: SimpleCommandLinePropertySource and
JOptCommandLinePropertySource.
Prior to this commit, JOptCommandLinePropertySource supported empty
values for optional arguments; whereas, SimpleCommandLinePropertySource
did not.
This commit modifies the implementation of SimpleCommandLinePropertySource
to allow empty values for optional arguments.
Closes gh-24464
The case of one data buffer containing multiple lines can could cause
a buffer leak due to a suspected issue in concatMapIterable. This
commit adds workarounds for that until the underlying issue is
addressed.
Closes gh-24339
The converter now tries to keep reading from the same InputStream which
should be possible with ordered and non-overlapping regions. When
necessary the InputStream is re-opened.
Closes gh-24214
Prior to Spring Framework 5.2, most annotation search algorithms made
use of AnnotationUtils.handleIntrospectionFailure() to handle exceptions
thrown while attempting to introspect annotation metadata. With the
introduction of the new MergedAnnotation API in Spring Framework 5.2,
this exception handling was accidentally removed.
This commit introduces the use of handleIntrospectionFailure() within
the new MergedAnnotation internals in order to (hopefully) align with
the previous behavior.
Closes gh-24188
Prior to this commit, when searching for annotations using the
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES strategy an exception could be
thrown while attempting to load the enclosing class (e.g., a
NoClassDefFoundError), thereby halting the entire annotation scanning
process.
This commit makes this search strategy defensive by logging exceptions
encountered while processing the enclosing class hierarchy instead of
allowing the exception to halt the entire annotation scanning process.
The exception handling is performed by
AnnotationUtils.handleIntrospectionFailure() which only allows an
AnnotationConfigurationException to propagate.
See gh-24136
Prior to this commit, the enclosing class was always eagerly loaded
even if the annotation search strategy was not explicitly
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES.
See gh-24136
Given the following improperly configured composed @RequestMapping
annotation:
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping
@interface PostApi {
@AliasFor("value")
String[] path() default {};
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] value() default {};
}
Prior to this commit, an attempt to process the above annotation
resulted in an exception similar to the following, which is not
especially helpful to discern the problem.
> Attribute 'value' in annotation [PostApi] must be declared as an
> @AliasFor 'path', not 'path'.
This commit improves the exception message for such scenarios,
resulting in an exception message similar to the following.
> Attribute 'value' in annotation [PostApi] must be declared as an
> @AliasFor attribute 'path' in annotation [PostApi], not attribute
> 'path' in annotation [RequestMapping].
Closes gh-24168
Update `ResolvableType` so that variable referenced can be resolved
against wildcard types. Prior to this commit, given a type:
Map<String, ? extends List<? extends CharSequence>>
Calling `type.getGeneric(1).asCollection().resolveGeneric()` would
return `null`. This was because the `List` variable `E` referenced a
wildcard type which `resolveVariable` did not support.
Closes gh-24145
Spring Framework 5.2 introduced a regression for implicit aliases
declared via @AliasFor. Specifically, Spring's merged annotation
algorithms stopped honoring default values for implicit alias pairs if
the composed annotation was used without specifying the aliased
attributes.
This commit fixes this regression.
Closes gh-24110
Spring Framework 5.2 introduced a regression in reflection-based
AnnotationMetadata. Specifically, as of 5.2, StandardAnnotationMetadata
no longer found @Inherited annotations from superclasses.
This commit fixes this regression by switching to the INHERITED_ANNOTATIONS
SearchStrategy when creating the MergedAnnotations used within
StandardAnnotationMetadata,
Note, however, that the discrepancy between StandardAnnotationMetadata
and SimpleAnnotationMetadata (i.e., reflection-based vs. ASM-based)
regarding @Inherited support still remains as it was prior to Spring
Framework 5.2.
Closes gh-24077
This commit introduces failing assertions that are currently disabled
via a boolean reproduceGh24077 flag.
Setting that flag to true demonstrates the regression for
StandardAnnotationMetadata and inconsistencies for SimpleAnnotationMetadata.
See gh-24077
This commit refines Coroutines annotated controller support
by considering Kotlin Unit as Java void and using the right
ReactiveAdapter to support all use cases, including suspending
functions that return Flow (usual when using APIs like WebClient).
It also fixes RSocket fire and forget handling and adds related tests
for that use case.
Closes gh-24057
Closes gh-23866
This commit adds support for Continuation parameter that is now
considered as an optional parameter since it is never provided by
the user.
It also simplifies and optimizes the implementation.
Closes gh-23991
Prior to this commit, the TestGroup.CI enum constant was only used in a
single test method in spring-core. In order to enable that test, the
`testGroups` JVM system property was configured for the
Publication-master CI build plan; however, the `testGroups` system
property is not set when executing local builds. Consequently, there
has been a Gradle cache miss for every `test` task when building
something locally that's already been built on the CI server.
This commit addresses this issue by removing the `TestGroup.CI` enum
constant. The `-PtestGroups=ci` command line configuration for the
Publication-master CI build plan has also been removed on the CI server.
Closes gh-23918
- Add maxInMemorySize property to Decoder and HttpMessageReader
implementations that aggregate input to trigger
DataBufferLimitException when reached.
- For codecs that call DataBufferUtils#join, there is now an overloaded
variant with a maxInMemorySize extra argument. Internally, a custom
LimitedDataBufferList is used to count and enforce the limit.
- Jackson2Tokenizer and XmlEventDecoder support those limits per
streamed JSON object.
See gh-23884
Update `AnnotationTypeMappings` so that a custom `RepeatableContainers`
instances can be used. Prior to this commit, only standard repeatables
were used when reading the annotations. This works in most situations,
but causes regressions for some `AnnotationUtils` methods.
Fixed gh-23856
Update `TypeMappedAnnotation` mirror resolution logic so that mapped
annotation values are also considered. Prior to this commit, mirrors
in more complex meta-annotation scenarios would not resolve correctly.
Specifically, given the following:
@interface TestAliased {
@AliasFor(attribute = "qualifier")
String value() default "";
@AliasFor(attribute = "value")
String qualifier() default "";
}
@TestAliased
@interface TestMetaAliased {
@AliasFor(annotation = Aliased.class, attribute = "value")
String value() default "";
}
@TestMetaAliased("test")
@interface TestComposed {
}
A merged `@TestAliased` annotation obtained from a `@TestComposed`
root annotation would return a `value` and `qualifier` of "".
This was because the "value" and "qualifier" mirrors needed to be
resolved against the `@TestMetaAliased` meta-annotation. They cannot be
resolved against the declared `@TestComposed` annotation because it
does not have any attributes. Our previous tests only covered a single
depth scenario where `@TestMetaAliased` was used directly on the
annotated element.
Closes gh-23767
Co-authored-by: Sam Brannen <sbrannen@pivotal.io>
Prior to this commit, it was not readily apparent what terms and units
such as kilobyte/KB and megabyte/MB represented numerically in DataSize
and DataUnit.
This commit clarifies that such terms and units are based on binary
prefixes for data (i.e., powers of 2 instead of powers of 10).
Closes gh-23697
This commit makes sure that DefaultResourceLoader consistently use
getProtocolResolvers() to access additional protocol resolvers. This
allows subclasses to define how the list is provided.
Closes gh-23564
Prior to this commit, a lot of work had been done to prevent improper
use of testing Framework APIs throughout the codebase; however, there
were still some loopholes.
This commit addresses these loopholes by introducing additional
Checkstyle rules (and modifying existing rules) to prevent improper use
of testing framework APIs in production code as well as in test code.
- Checkstyle rules for banned imports have been refactored into
multiple rules specific to JUnit 3, JUnit 4, JUnit Jupiter, and
TestNG.
- Accidental usage of org.junit.Assume has been switched to
org.junit.jupiter.api.Assumptions.
- All test classes now reside under org.springframework packages.
- All test classes (including abstract test classes) now conform to the
`*Tests` naming convention.
- As an added bonus, tests in the renamed
ScenariosForSpringSecurityExpressionTests are now included in the
build.
- Dead JUnit 4 parameterized code has been removed from
DefaultServerWebExchangeCheckNotModifiedTests.
Closes gh-22962
Prior to this commit, Spring failed to determine that an XML config file
was DTD-based if the DTD declaration was followed by a comment.
This commit fixes this by modifying the consumeCommentTokens(String)
algorithm in XmlValidationModeDetector so that both leading and trailing
comments are properly consumed without losing any XML content.
Closes gh-23605
MergedAnnotations provides 'from' variants with RepeatableContainers but without AnnotationFilter argument now, avoiding the need to refer to AnnotationFilter.PLAIN as a default at call sites.
The org.reactivestreams has 13 instead of 4 classes in 1.0.3 with the
addition of Java 9 Flow adapters. This commit switches to using a
different package reactor.util.annotation, also with a small number of
classes, for this test.
Prior to this commit, ClassUtils.isPrimitiveOrWrapper() and
ClassUtils.isPrimitiveWrapper() did not return true for Void.class.
However, ClassUtils.isPrimitiveOrWrapper() did return true for
void.class. This lacking symmetry is inconsistent and can lead to bugs
in reflective code.
See: https://github.com/spring-projects/spring-data-r2dbc/issues/159
This commit addresses this by adding an entry for Void.class -> void.class
in the internal primitiveWrapperTypeMap in ClassUtils.
Closes gh-23572
Prior to this commit, the Spring Framework build would partially use the
dependency management plugin to import and enforce BOMs.
This commit applies the dependency management plugin to all Java
projects and regroups all version management declaration in the root
`build.gradle` file (versions and exclusions).
Some versions are overridden in specific modules for
backwards-compatibility reasons or extended support.
This commit also adds the Gradle versions plugin that checks for
dependency upgrades in artifact repositories and produces a report; you
can use the following:
./gradlew dependencyUpdates
This commit makes sure that reading is enabled after the current
signal has been processed, not while is is being processed. The bug
was only apparent while using the JettyClientHttpConnector, which
requests new elements continuously, even after the end of the
stream has been signalled.
This commit prepends "[{index}] " to all custom display names
configured via @ParameterizedTest.
This provides better diagnostics between the "technical names" reported
on the CI server vs. the "display names" reported within a developer's
IDE.
See gh-23451
This commit introduces a test that verifies that
PathMatchingResourcePatternResolver can find files in the filesystem
that contain hashtags (#) in their names.
See gh-23532
Instead of relying on the CI server to apply and configure this plugin,
this commit does it directly in the Spring Framework build.
This allows us to take full control over which projects are published
and how.
See gh-23282
Prior to this commit, the build would use a custom task to create a BOM
and manually include/exclude/customize dependencies. It would also use
the "maven" plugin to customize the POM before publication.
This commit now uses a Gradle Java Platform for publishing the Spring
Framework BOM. We're also now using the "maven-publish" plugin to
prepare and customize publications.
This commit also tells the artifactory plugin (which is currently
applied only on the CI) not to publish internal modules.
See gh-23282
Prior to this commit, the Spring Framework build would mix proper
framework modules (spring-* modules published to maven central) and
internal modules such as:
* "spring-framework-bom" (which publishes the Framework BOM with all
modules)
* "spring-core-coroutines" which is an internal modules for Kotlin
compilation only
This commit renames these modules so that they don't start with
"spring-*"; we're also moving the "kotlin-coroutines" module under
"spring-core", since it's merged in the resulting JAR.
See gh-23282
This commit reorganizes tasks and scripts in the build to only apply
them where they're needed. We're considering here 3 "types" of projects
in our build:
* the root project, handling documentation, publishing, etc
* framework modules (a project that's published as a spring artifact)
* internal modules, such as the BOM, our coroutines support and our
integration-tests
With this change, we're strealining the project configuration for all
spring modules and only applying plugins when needed (typically our
kotlin support).
See gh-23282
Due to a bug (or "unintentional feature") in JUnit 4, overridden test
methods not annotated with @Test are still executed as test methods;
however, JUnit Jupiter does not support that. Thus, prior to this
commit, some overridden test methods in spring-core were no longer
executed after the migration from JUnit 4 to JUnit Jupiter.
This commit addresses this issue for such known use cases, but there
are likely other such use cases within Spring's test suite.
See gh-23451
This commit removes the JUnit 4 dependency from all modules except
spring-test which provides explicit JUnit 4 support.
This commit also includes the following.
- migration from JUnit 4 assertions to JUnit Jupiter assertions in all
Kotlin tests
- migration from JUnit 4 assumptions in Spring's TestGroup support to
JUnit Jupiter assumptions, based on org.opentest4j.TestAbortedException
- introduction of a new TestGroups utility class than can be used from
existing JUnit 4 tests in the spring-test module in order to perform
assumptions using JUnit 4's Assume class
See gh-23451
This commit migrates parameterized tests in spring-core using the
"composed @ParameterizedTest" approach. This approach is reused in
follow-up commits for the migration of the remaining modules.
For a concrete example, see AbstractDataBufferAllocatingTests and its
subclasses (e.g., DataBufferTests).
Specifically, AbstractDataBufferAllocatingTests declares a custom
@ParameterizedDataBufferAllocatingTest annotation that is
meta-annotated with @ParameterizedTest and
@MethodSource("org.springframework.core.io.buffer.AbstractDataBufferAllocatingTests#dataBufferFactories()").
Individual methods in concrete subclasses are then annotated with
@ParameterizedDataBufferAllocatingTest instead of @ParameterizedTest or
@Test.
The approach makes the migration from JUnit 4 to JUnit Jupiter rather
straightforward; however, there is one major downside. The arguments
for a @ParameterizedTest test method can only be accessed by the test
method itself. It is not possible to access them in an @BeforeEach
method (see https://github.com/junit-team/junit5/issues/944).
Consequently, we are forced to declare the parameters in each such
method and delegate to a custom "setup" method. Although this is a bit
cumbersome, I feel it is currently the best way to achieve fine grained
parameterized tests within our test suite without implementing a custom
TestTemplateInvocationContextProvider for each specific use case.
Once https://github.com/junit-team/junit5/issues/878 is resolved, we
should consider migrating to parameterized test classes.
See gh-23451
This first commit for this issue:
- allows JUnit Jupiter to be used for all tests
- adds a dependency on mockito-junit-jupiter
- migrates tests in spring-core to JUnit Jupiter, except parameterized
tests
The following script was developed in order to semi-automate the
migration process.
https://github.com/sbrannen/junit-converters/blob/master/junit4ToJUnitJupiter.zsh
See gh-23451
ClassLoaderAwareUndeclaredThrowableStrategy fails with a VerifyError on recent JDKs after the CGLIB 3.3 upgrade. The alternative is to replace it with a plain ClassLoaderAwareGeneratorStrategy (extracted from CglibSubclassingInstantiationStrategy) and custom UndeclaredThrowableException handling in CglibMethodInvocation.
See gh-23453
Prior to this commit, StopWatch used System.currentTimeMillis() to
track and report running time in milliseconds.
This commit updates the internals of StopWatch to use System.nanoTime()
instead of System.currentTimeMillis(). Consequently, running time is
now tracked and reported in nanoseconds; however, users still have the
option to retrieve running time in milliseconds or seconds.
Closes gh-23235
Since arbitrary levels of proxies do not occur, this commit replaces
the `while` loop in SerializableTypeWrapper.unwrap() with a simple
`if` statement.
Closes gh-23415
Since Java 8, putIfAbsent() is a standard method in java.util.Map. We
therefore no longer need the custom implementation that overrides the
standard implementation in HashMap.
Prior to this commit, AnnotationAttributes#assertNotException checked if
the attribute value was an instance of Exception. Although this was
typically sufficient, the scope was not always broad enough -- for
example, if AnnotationReadingVisitorUtils#convertClassValues stored a
Throwable in the map (such as a LinkageError).
This commit fixes this by checking for an instance of Throwable in
AnnotationAttributes#assertNotException.
Closes gh-23424
Deprecate all mutation methods in `MethodParameter` in favor of factory
methods that return a new instance. Existing code that previously relied
on mutation has been updated to use the replacement methods.
Closes gh-23385
Prior to this commit, the new `TYPE_HIERARCHY_AND_ENCLOSING_CLASSES`
annotation search strategy failed to find annotations on enclosing
classes if the source class was a nested class that itself had no
annotations present.
This commit fixes this by adding special logic to AnnotationsScanner's
isWithoutHierarchy() method to properly support nested classes.
Closes gh-23378
Add a `TYPE_HIERARCHY_AND_ENCLOSING_CLASSES` annotation search strategy
that can be used to search the full type hierarchy as well as any
enclosing classes.
Closes gh-23378
Update code that's often called so that zero length array results use
a single shared static constant, rather than a new instance for each
call.
Closes gh-23340
This commit upgrades Coroutines support to kotlinx.coroutines
1.3.0-RC, leverages the new Coroutines BOM and refine Coroutines
detection to avoid false positives.
Only Coroutines to Mono context interoperability is supported
for now.
CLoses gh-23326
Fix `isAssignable` for `ResolvableType.forRawClass` so that it can be
used with types backed by a `TypeVarible`. Prior to this commit the
rawClass value was used, which wouldn't always work.
Closes gh-23321
Prior to this commit, a null path supplied to the isPattern(), match(),
and matchStart() methods in AntPathMatcher resulted in a
NullPointerException.
This commit addresses this by treating a `null` path as a non-matching
pattern.
Closes gh-23297
This commit refactors the internals of
LocalVariableTableParameterNameDiscoverer to use
java.lang.reflect.Executable in order to simplify the implementation.
DataBuffers::split (and underlying algorithm) should not be returning
a Flux<DataBuffer>, but rather a Flux<Flux<DataBuffer>>. In other words,
it should not join all data buffers that come before a delimiter.
Providing an implementation of a such a fully reactive split method
proved to be beyond the scope of this release, so this commit removes
the method altogether.
Due to the imminent removal of DataBufferUtils.split, this commit copies
over the buffering split algortihm from DataBufferUtils, as it is still
sutable for the StringDecoder
The new annotation helps to differentiate the handling of connection
level frames (SETUP and METADATA_PUSH) from the 4 stream requests.
Closes gh-23177
Prior to Spring Framework 5.1.3, MimeTypeUtils.parseMimeTypes() and
MediaType.parseMediaTypes() ignored empty entries, but 5.1.3 introduced
a regression in that an empty entry -- for example, due to a trailing
comma in the list of media types in an HTTP Accept header -- would result
in a "406 Not Acceptable" response status.
This commit fixes this by filtering out empty entries before parsing
them into MimeType and MediaType instances. Empty entries are therefore
effectively ignored.
Fixes gh-23241
Update `MimeTypeUtils` so that the StringUtils.hasLength check is
performed immediately on the incoming argument, rather than in
`parseMimeTypeInternal`. This restores the `IllegalArgumentException`
rather than the `NullPointerException` which is thrown by the
`ConcurrentHashMap`.
Closes gh-23215
See gh-23211
This commit improves the cache implementation by skipping the ordering
of most recently used cached keys when the cache is at least half empty.
See gh-23211
As of gh-22340, `MimeTypeUtils` has a built-in LRU cache implementation
for caching parsed MIME types and avoiding excessive garbage creation at
runtime.
This implementation, when hit with highly concurrent reads on the same
media type (the cache key), can create multiple keys for the same MIME
type string. This duplication leads to the cache filling up and evicting
entries. When the cache fetches a duplicate key, it is then not
associated with a value and the cache can return a `null` value, which
is forbidden by the API contract.
This commit adds another cache check within the write lock: this avoids
creating duplicate entries in the cache and `null` return values.
Fixes gh-23211
This commit clarifies the semantics of the PriorityOrdered interface
with respect to sorting sets of objects containing both PriorityOrdered
and plain Ordered objects.
Closes gh-23187