Given a @Configuration class named org.example.AppConfig which
contains @Bean methods, in Spring Framework 5.3.x and previous
versions, the following classes were created when generating the CGLIB
proxy.
org.example.AppConfig$$EnhancerBySpringCGLIB$$fd7e9baa
org.example.AppConfig$$FastClassBySpringCGLIB$$3fec86e
org.example.AppConfig$$EnhancerBySpringCGLIB$$fd7e9baa$$FastClassBySpringCGLIB$$82534900
Those class names indicate that 1 class was generated for the proxy for
the @Configuration class itself and that 2 additional FastClass
classes were generated to support proxying of @Bean methods in
superclasses.
However, since Spring Framework 6.0, the following classes are created
when generating the CGLIB proxy.
org.example.AppConfig$$SpringCGLIB$$0
org.example.AppConfig$$SpringCGLIB$$1
org.example.AppConfig$$SpringCGLIB$$2
The above class names make it appear that 3 proxy classes are generated
for each @Configuration class, which is misleading.
To address that and to align more closely with how such generated
classes were named in previous versions of the framework, this commit
modifies SpringNamingPolicy so that generated class names once again
include "FastClass" when the generated class is for a CGLIB FastClass
as opposed to the actual proxy for the @Configuration class.
Consequently, with this commit the following classes are created when
generating the CGLIB proxy.
org.example.AppConfig$$SpringCGLIB$$0
org.example.AppConfig$$SpringCGLIB$$FastClass$$0
org.example.AppConfig$$SpringCGLIB$$FastClass$$1
Closes gh-31272
The introduction of AdvisedSupport.AdvisorKeyEntry in Spring Framework
6.0.10 resulted in a regression regarding caching of CGLIB generated
proxy classes. Specifically, equality checks for the proxy class cache
became based partially on identity rather than equivalence. For
example, if an ApplicationContext was configured to create a
class-based @Transactional proxy, a second attempt to create the
ApplicationContext resulted in a duplicate proxy class for the same
@Transactional component.
On the JVM this went unnoticed; however, when running Spring
integration tests within a native image, if a test made use of
@DirtiesContext, a second attempt to create the test
ApplicationContext resulted in an exception stating, "CGLIB runtime
enhancement not supported on native image." This is because Test AOT
processing only refreshes a test ApplicationContext once, and the
duplicate CGLIB proxy classes are only requested in subsequent
refreshes of the same ApplicationContext which means that duplicate
proxy classes are not tracked during AOT processing and consequently
not included in a native image.
This commit addresses this regression as follows.
- AdvisedSupport.AdvisorKeyEntry is now based on the toString()
representations of the ClassFilter and MethodMatcher in the
corresponding Pointcut instead of the filter's and matcher's
identities.
- Due to the above changes to AdvisorKeyEntry, ClassFilter and
MethodMatcher implementations are now required to implement equals(),
hashCode(), AND toString().
- Consequently, the following now include proper equals(), hashCode(),
and toString() implementations.
- CacheOperationSourcePointcut
- TransactionAttributeSourcePointcut
- PerTargetInstantiationModelPointcut
Closes gh-31238
This commit reverts the deprecation of CommandLinePropertySource and
SimpleCommandLinePropertySource, since we have discovered that Spring
Boot actively uses SimpleCommandLinePropertySource in
org.springframework.boot.SpringApplication.
Closes gh-31207
This commit deprecates the various nullSafeHashCode methods taking array
types as they are superseded by Arrays.hashCode now. This means that
the now only remaining nullSafeHashCode method does not trigger a
warning only if the target type is not an array. At the same time, there
are multiple use of this method on several elements, handling the
accumulation of hash codes.
For that reason, this commit also introduces a nullSafeHash that takes
an array of elements. The only difference between Objects.hash is that
this method handles arrays.
The codebase has been reviewed to use any of those two methods when it
is possible.
Closes gh-29051
AnnotationBeanNameGenerator was written before the introduction of the
MergedAnnotations API and therefore heavily relies on the
AnnotationMetadata abstraction and various helper methods for ASM
compatibility.
However, recent work on determineBeanNameFromAnnotation() has made it
apparent that we should use the MergedAnnotations API directly in
AnnotationBeanNameGenerator where feasible in order to avoid
unnecessary, repeated iterations/streams over the same annotation
metadata.
Closes gh-31203
This commit allows a custom code fragment to provide the code to
create a bean without relying on ConstructorResolver. This is especially
important for use cases that derive from the default behaviour and
provide an instance supplier with the regular runtime scenario.
This is a breaking change for code fragments providing a custom
implementation of the related methods. As it turns out, almost all of
them did not need the Executable argument. Configuration class parsing
is the exception, where it needs to provide a different constructor in
the case of the proxy. To make this use case possible,
InstanceSupplierCodeGenerator has been made public.
Closes gh-31117
This commit prints a log message at debug level without
a stacktrace for TypeNotPresentException and uses
warn level instead of error level for other exceptions
since the processing of such bean will just be skipped.
Closes gh-31147
When use of the deprecated feature is detected, a WARNING log message
will be generated analogous to the following.
WARN o.s.c.a.AnnotationBeanNameGenerator - Support for convention-based
stereotype names is deprecated and will be removed in a future version
of the framework. Please annotate the 'value' attribute in
@org.springframework.context.annotation.AnnotationBeanNameGeneratorTests$ConventionBasedComponent1
with @AliasFor(annotation=Component.class) to declare an explicit alias
for @Component's 'value' attribute.
See gh-31089
Closes gh-31093
This commit builds on the recently added support for using @AliasFor to
override the `value` attribute in `@Component, and allows a custom
component name to be specified in both @ControllerAdvice and
@RestControllerAdvice via new `name` attributes.
See gh-31089
Closes gh-21108
Although gh-20615 introduced the use of @AliasFor for @Component(value) in the built-in
stereotype annotations (@Service, @Controller, @Repository, @Configuration, and
@RestController), prior to this commit the framework did not actually rely on @AliasFor
support when looking up a component name via stereotype annotations. Rather, the
framework had custom annotation parsing logic in
AnnotationBeanNameGenerator#determineBeanNameFromAnnotation() which effectively ignored
explicit annotation attribute overrides configured via @AliasFor.
This commit revises AnnotationBeanNameGenerator#determineBeanNameFromAnnotation() so that
it first looks up @Component stereotype names using @AliasFor semantics before falling
back to the "convention-based" component name lookup strategy.
Consequently, the name of the annotation attribute that is used to specify the bean name
is no longer required to be `value`, and custom stereotype annotations can now declare an
attribute with a different name (such as `name`) and annotate that attribute with
`@AliasFor(annotation = Component.class, attribute = "value")`.
Closes gh-31089
This commit reinstates support for the legacy JSR-250
@javax.annotation.ManagedBean and JSR-330 @javax.inject.Named
annotations with regard to component name lookups and component
scanning.
Closes gh-31090
Prior to this commit, there was an issue with the semantics of property
source overrides. Specifically, a @PropertySource annotation present as
a meta-annotation on a @Configuration class was registered with higher
precedence than a @PropertySource annotation declared closer to (or
directly on) the @Configuration class. Consequently, there was no way
for a "local" @PropertySource annotation to override properties
registered via @PropertySource as a meta-annotation.
This commit addresses this issue by introducing a new overloaded
getMergedRepeatableAnnotationAttributes() variant in
AnnotatedTypeMetadata that allows the caller to supply a
sortByReversedMetaDistance flag. When set to `true`, the annotation
search results will be sorted in reversed order based on each
annotation's meta distance, which effectively orders meta-annotations
before annotations that are declared directly on the underlying element.
ConfigurationClassParser and AnnotationConfigUtils have been updated to
use this new repeatable annotation search method for @PropertySource.
Closes gh-31074
Reuses ValidationAnnotationUtils which is slightly optimized for the detection of Spring's Validated annotation now, also to the benefit of common web scenarios.
Closes gh-21852
Prior to this commit, Spring failed to find multiple composed
@ComponentScan and @PropertySource annotations or multiple
@ComponentScans and @PropertySources container annotations. The reason
was due to lacking support in the AnnotatedTypeMetadata API.
This commit introduces support for finding all @ComponentScan and
@PropertySource annotations by making use of the new
getMergedRepeatableAnnotationAttributes() method in
AnnotatedTypeMetadata.
Closes gh-30941
See gh-31041
Java 12 introduced java.lang.Class#componentType() as a shortcut for
getComponentType().
Since we started using arrayType() in fe5560400c, this commit switches
to componentType() for consistent API usage style.
This commit allows to configure custom file
extensions in ReloadableResourceBundleMessageSource
thanks to a new setFileExtensions setter.
Combined with setPropertiesPersister, it allows
custom implementations supporting any kind of
property file.
Closes gh-18990
TransactionalApplicationListener and TransactionalEventListener automatically detect a reactive TransactionContext as the event source and register the synchronization accordingly. TransactionalEventPublisher is a convenient delegate for publishing corresponding events with the current TransactionContext as event source. This can also serve as a guideline for similar reactive event purposes.
Closes gh-27515
Closes gh-21025
Closes gh-30244
Includes CompletableFuture-based retrieve operations on Spring's Cache interface.
Includes support for retrieve operations on CaffeineCache and ConcurrentMapCache.
Includes async cache mode option on CaffeineCacheManager.
Closes gh-17559
Closes gh-17920
Closes gh-30122
Includes failOnError method on Errors interface for use with validateObject.
Declares many Errors methods as default methods for lean SimpleErrors class.
Closes gh-19877
Prior to this commit a @CachePut operation would fail if the key
expression is invalid, but guarded with an unless condition as the
former was evaluated too early. This commit makes sure that key for
a put is only evaluated if the put operation is active.
Note that this does not apply for @Cacheable as the key needs to be
computed early to determine if a matching entry exists in the cache.
See gh-22769
After further consideration, the team has decided to remove the
getAutodetectMode() method since its return type conflicts with the
parameter type in setAutodetectMode(int), making it an invalid bean
property.
See gh-30855
Prior to this commit, MBeanExporter used
org.springframework.core.Constants which used reflection to find
constant fields in the MBeanExporter class. Consequently, one had to
register reflection hints in order to use MBeanExporter in a GraalVM
native image.
This commit addresses this by replacing the use of the `Constants`
class with a simple java.util.Map which maps constant names to constant
values for the autodetect constants defined in MBeanExporter.
See gh-30851
Closes gh-30846
This merges the existing support for the legacy JSR-250 PostConstruct/PreDestroy annotations into CommonAnnotationBeanPostProcessor itself, opening up the InitDestroyAnnotationBeanPostProcessor base class for multiple init/destroy methods in a single post-processor. This removes the need for a separate JSR-250 InitDestroyAnnotationBeanPostProcessor in AnnotationConfigUtils.
Closes gh-30695
We would preferably use ObjectUtils.nullSafeConciseToString(rejectedValue) here but revert to the full nullSafeToString representation for strict backwards compatibility (programmatic toString calls as well as exception messages).
Closes gh-30799
Prior to this commit, private (and non-visible package-private)
init/destroy methods were not supported in AOT mode. The reason is that
such methods are tracked using their fully-qualified method names, and
the AOT support for init/destroy methods previously did not take
fully-qualified method names into account. In addition, the invocation
order of init/destroy methods differed vastly between standard JVM mode
and AOT mode.
This commit addresses these issues in the following ways.
- AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(),
DisposableBeanAdapter.determineDestroyMethod(), and
BeanDefinitionPropertiesCodeGenerator.addInitDestroyHint() now parse
fully-qualified method names to locate the correct init/destroy
methods.
- AbstractAutowireCapableBeanFactory and DisposableBeanAdapter delegate
to a new MethodDescriptor record which encapsulates the parsing of
fully-qualified method names; however,
BeanDefinitionPropertiesCodeGenerator duplicates this logic since it
resides in a different package, and we do not currently want to make
MethodDescriptor public.
- Init/destroy methods detected via annotations (such as @PostConstruct
and @PreDestroy) are now invoked prior to init/destroy methods that
are explicitly configured by name or convention. This aligns with the
invocation order in standard JVM mode; however,
InitializingBean#afterPropertiesSet() and DisposableBean#destroy()
are still invoked before annotated init/destroy methods in AOT mode
which differs from standard JVM mode.
- Unit and integration tests have been updated to test the revised
behavior.
Closes gh-30692
Extract the default logic for resolving the name of an @Valid
parameter into an ObjectNameResolver, and use it when there isn't
one configured.
See gh-30644
To handle method validation errors in ResponseEntityExceptionHandler,
MethodValidationException and associated types should not depend on
Bean Validation. To that effect:
1. MethodValidationResult and ParameterValidationResult no longer make
the underlying ConstraintViolation set available, and instead expose
only the adapted validation errors (MessageSourceResolvable, Errors),
analogous to what SpringValidatorAdapter does. And likewise
MethodValidationException no longer extends ConstraintViolationException.
2. MethodValidationPostProcessor has a new property
adaptConstraintViolations to decide whether to simply raise
ConstraintViolationException, or otherwise to adapt the ConstraintViolations
and raise MethodValidationException instead, with the former is the default
for compatibility.
3. As a result, the MethodValidator contract can now expose methods that
return MethodValidationResult, which provided more flexibility for handling,
and it allows MethodValidationAdapter to implement MethodValidator directly.
4. Update Javadoc in method validation classes to reflect this shift, and
use terminology consistent with Spring validation in classes without an
explicit dependency on Bean Validation.
See gh-30644
Remove throwIfViolationsPresent and replace with static factory
methods on MethodValidationException taking MethodValidationResult,
which makes handling more explicit and allows choice of what
exception to raise.
Update MethodValidationResult to expose the target, the method, and
forReturnValue flag, so the code handling an exception will have
access to all details.
See gh-30644
This commit updates the `ScheduledTaskObservationDocumentation` to
better align the contributed KeyValues with OpenTelemetry conventions
for observations of code executions.
Instead of a "target.type" key with the bean class simple name, this
is now contributing the canonical class name of the bean under the
"code.namespace" key.
The "method.name" key is renamed to "code.function" and its values
remain unchanged.
Closes gh-30721
Prior to this commit, if an init/destroy method was package-private and
declared in a superclass in a package different from the package in
which the registered bean resided, a local init/destroy method with the
same name would effectively "shadow" the method from the different
package, resulting in only the local init/destroy method being invoked.
This commit addresses this issue by tracking package-private init
methods from different packages using their fully-qualified method
names, analogous to the existing support for private init/destroy
methods.
Closes gh-30718
Previously, a bean definition that is optimized AOT could have
different metadata based on whether its resolved type had a generic or
not. This is due to RootBeanDefinition taking either a Class or a
ResolvableType doing fundamentally different things. While the former
sets the bean class which is to little use with an instance supplier,
the latter specifies the target type of the bean.
This commit sets the target type of the bean, using the existing
setter methods that take either a class or a ResolvableType and set the
same attribute consistently.
Closes gh-30689
This commit enhances the `ScheduledAnnotationBeanPostProcessor` to
instrument `@Scheduled` methods declared on beans. This will create
`"tasks.scheduled.execution"` observations for each execution of a
scheduled method. This supports both blocking and reactive variants.
By default, observations are no-ops; developers must configure the
current `ObservationRegistry` on the `ScheduledTaskRegistrar` by using a
`SchedulingConfigurer`.
Closes gh-29883