From 9bc09631d61e2d011972232a5b32c1edc51c6dcf Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 9 Nov 2021 22:29:56 +0100 Subject: [PATCH 1/4] Recommend ObjectProvider as alternative to @Lazy for optional dependencies Closes gh-27649 --- .../org/springframework/context/annotation/Lazy.java | 7 ++++++- src/docs/asciidoc/core/core-beans.adoc | 10 ++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/annotation/Lazy.java b/spring-context/src/main/java/org/springframework/context/annotation/Lazy.java index 9d04a9df26e..8369957f591 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/Lazy.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/Lazy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2021 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. @@ -47,6 +47,11 @@ import java.lang.annotation.Target; * or {@link javax.inject.Inject}: In that context, it leads to the creation of a * lazy-resolution proxy for all affected dependencies, as an alternative to using * {@link org.springframework.beans.factory.ObjectFactory} or {@link javax.inject.Provider}. + * Please note that such a lazy-resolution proxy will always be injected; if the target + * dependency does not exist, you will only be able to find out through an exception on + * invocation. As a consequence, such an injection point results in unintuitive behavior + * for optional dependencies. For a programmatic equivalent, allowing for lazy references + * with more sophistication, consider {@link org.springframework.beans.factory.ObjectProvider}. * * @author Chris Beams * @author Juergen Hoeller diff --git a/src/docs/asciidoc/core/core-beans.adoc b/src/docs/asciidoc/core/core-beans.adoc index 5ba741761f2..8d701befcbc 100644 --- a/src/docs/asciidoc/core/core-beans.adoc +++ b/src/docs/asciidoc/core/core-beans.adoc @@ -3039,7 +3039,7 @@ constructor or setter argument or autowired field) as `ObjectFactory`, which delivers +As an extended variant, you may declare `ObjectProvider` which delivers several additional access variants, including `getIfAvailable` and `getIfUnique`. The JSR-330 variant of this is called `Provider` and is used with a `Provider` @@ -6675,9 +6675,11 @@ factory method and other bean definition properties, such as a qualifier value t the `@Qualifier` annotation. Other method-level annotations that can be specified are `@Scope`, `@Lazy`, and custom qualifier annotations. -TIP: In addition to its role for component initialization, you can also place the `@Lazy` annotation -on injection points marked with `@Autowired` or `@Inject`. In this context, it -leads to the injection of a lazy-resolution proxy. +TIP: In addition to its role for component initialization, you can also place the `@Lazy` +annotation on injection points marked with `@Autowired` or `@Inject`. In this context, +it leads to the injection of a lazy-resolution proxy. However, such a proxy approach +is rather limited. For sophisticated lazy interactions, in particular in combination +with optional dependencies, we recommend `ObjectProvider` instead. Autowired fields and methods are supported, as previously discussed, with additional support for autowiring of `@Bean` methods. The following example shows how to do so: From 8d735e6e605737f561252bb4e629c8fb160b9ddf Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 9 Nov 2021 22:30:44 +0100 Subject: [PATCH 2/4] Note on PersistenceExceptionTranslator sorting and non-singleton retrieval Closes gh-26412 --- .../PersistenceExceptionTranslationPostProcessor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spring-tx/src/main/java/org/springframework/dao/annotation/PersistenceExceptionTranslationPostProcessor.java b/spring-tx/src/main/java/org/springframework/dao/annotation/PersistenceExceptionTranslationPostProcessor.java index c975e9ec6b0..a612fe808d0 100644 --- a/spring-tx/src/main/java/org/springframework/dao/annotation/PersistenceExceptionTranslationPostProcessor.java +++ b/spring-tx/src/main/java/org/springframework/dao/annotation/PersistenceExceptionTranslationPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2021 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. @@ -38,7 +38,6 @@ import org.springframework.util.Assert; * PersistenceExceptionTranslator} interface, which are subsequently asked to translate * candidate exceptions. * - *

All of Spring's applicable resource factories (e.g. * {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}) * implement the {@code PersistenceExceptionTranslator} interface out of the box. @@ -47,6 +46,11 @@ import org.springframework.util.Assert; * with the {@code @Repository} annotation, along with defining this post-processor * as a bean in the application context. * + *

As of 5.3, {@code PersistenceExceptionTranslator} beans will be sorted according + * to Spring's dependency ordering rules: see {@link org.springframework.core.Ordered} + * and {@link org.springframework.core.annotation.Order}. Note that such beans will + * get retrieved from any scope, not just singleton scope, as of this 5.3 revision. + * * @author Rod Johnson * @author Juergen Hoeller * @since 2.0 From b167e1a93fe299b19f339896d86e65337b05b78f Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 9 Nov 2021 22:35:24 +0100 Subject: [PATCH 3/4] Remove unnecessary final declarations (for consistency) --- .../AutowiredAnnotationBeanPostProcessor.java | 2 +- .../CommonAnnotationBeanPostProcessor.java | 4 ++-- .../annotation/ComponentScanAnnotationParser.java | 4 ++-- .../annotation/ConfigurationClassEnhancer.java | 14 +++++++------- .../PersistenceAnnotationBeanPostProcessor.java | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index e7131a562ef..37f5884e671 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -459,7 +459,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA return metadata; } - private InjectionMetadata buildAutowiringMetadata(final Class clazz) { + private InjectionMetadata buildAutowiringMetadata(Class clazz) { if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { return InjectionMetadata.EMPTY; } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java index 8a3ca5a9f88..ecfdf8f83a9 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java @@ -343,7 +343,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean } - private InjectionMetadata findResourceMetadata(String beanName, final Class clazz, @Nullable PropertyValues pvs) { + private InjectionMetadata findResourceMetadata(String beanName, Class clazz, @Nullable PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. @@ -363,7 +363,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean return metadata; } - private InjectionMetadata buildResourceMetadata(final Class clazz) { + private InjectionMetadata buildResourceMetadata(Class clazz) { if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) { return InjectionMetadata.EMPTY; } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java index 27e879bfb33..0a3c751ff39 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 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. @@ -65,7 +65,7 @@ class ComponentScanAnnotationParser { } - public Set parse(AnnotationAttributes componentScan, final String declaringClass) { + public Set parse(AnnotationAttributes componentScan, String declaringClass) { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java index 17079522c7f..1b215e524cc 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 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. @@ -453,8 +453,8 @@ class ConfigurationClassEnhancer { * instance directly. If a FactoryBean instance is fetched through the container via &-dereferencing, * it will not be proxied. This too is aligned with the way XML configuration works. */ - private Object enhanceFactoryBean(final Object factoryBean, Class exposedType, - final ConfigurableBeanFactory beanFactory, final String beanName) { + private Object enhanceFactoryBean(Object factoryBean, Class exposedType, + ConfigurableBeanFactory beanFactory, String beanName) { try { Class clazz = factoryBean.getClass(); @@ -489,8 +489,8 @@ class ConfigurationClassEnhancer { return createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName); } - private Object createInterfaceProxyForFactoryBean(final Object factoryBean, Class interfaceType, - final ConfigurableBeanFactory beanFactory, final String beanName) { + private Object createInterfaceProxyForFactoryBean(Object factoryBean, Class interfaceType, + ConfigurableBeanFactory beanFactory, String beanName) { return Proxy.newProxyInstance( factoryBean.getClass().getClassLoader(), new Class[] {interfaceType}, @@ -502,8 +502,8 @@ class ConfigurationClassEnhancer { }); } - private Object createCglibProxyForFactoryBean(final Object factoryBean, - final ConfigurableBeanFactory beanFactory, final String beanName) { + private Object createCglibProxyForFactoryBean(Object factoryBean, + ConfigurableBeanFactory beanFactory, String beanName) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(factoryBean.getClass()); diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java index d9ff7afc141..61582bee118 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -373,7 +373,7 @@ public class PersistenceAnnotationBeanPostProcessor } - private InjectionMetadata findPersistenceMetadata(String beanName, final Class clazz, @Nullable PropertyValues pvs) { + private InjectionMetadata findPersistenceMetadata(String beanName, Class clazz, @Nullable PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. @@ -393,7 +393,7 @@ public class PersistenceAnnotationBeanPostProcessor return metadata; } - private InjectionMetadata buildPersistenceMetadata(final Class clazz) { + private InjectionMetadata buildPersistenceMetadata(Class clazz) { if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(PersistenceContext.class, PersistenceUnit.class))) { return InjectionMetadata.EMPTY; } From 11a0df3fd144a8c792cd2f9d5a721d21abe52f2b Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 9 Nov 2021 22:36:11 +0100 Subject: [PATCH 4/4] Upgrade to Tomcat 9.0.54, Netty 4.1.70, HtmlUnit 2.54, XMLUnit 2.8.3 --- build.gradle | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 98c85c3d008..6021fa574dd 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ configure(allprojects) { project -> dependencyManagement { imports { mavenBom "com.fasterxml.jackson:jackson-bom:2.12.5" - mavenBom "io.netty:netty-bom:4.1.69.Final" + mavenBom "io.netty:netty-bom:4.1.70.Final" mavenBom "io.projectreactor:reactor-bom:2020.0.13" mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR10" mavenBom "io.rsocket:rsocket-bom:1.1.1" @@ -128,14 +128,14 @@ configure(allprojects) { project -> dependency "org.webjars:webjars-locator-core:0.48" dependency "org.webjars:underscorejs:1.8.3" - dependencySet(group: 'org.apache.tomcat', version: '9.0.53') { + dependencySet(group: 'org.apache.tomcat', version: '9.0.54') { entry 'tomcat-util' entry('tomcat-websocket') { exclude group: "org.apache.tomcat", name: "tomcat-websocket-api" exclude group: "org.apache.tomcat", name: "tomcat-servlet-api" } } - dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.53') { + dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.54') { entry 'tomcat-embed-core' entry 'tomcat-embed-websocket' } @@ -192,7 +192,7 @@ configure(allprojects) { project -> dependency "org.hamcrest:hamcrest:2.1" dependency "org.awaitility:awaitility:3.1.6" dependency "org.assertj:assertj-core:3.21.0" - dependencySet(group: 'org.xmlunit', version: '2.8.2') { + dependencySet(group: 'org.xmlunit', version: '2.8.3') { entry 'xmlunit-assertj' entry('xmlunit-matchers') { exclude group: "org.hamcrest", name: "hamcrest-core" @@ -206,10 +206,10 @@ configure(allprojects) { project -> } dependency "io.mockk:mockk:1.12.0" - dependency("net.sourceforge.htmlunit:htmlunit:2.53.0") { + dependency("net.sourceforge.htmlunit:htmlunit:2.54.0") { exclude group: "commons-logging", name: "commons-logging" } - dependency("org.seleniumhq.selenium:htmlunit-driver:2.53.0") { + dependency("org.seleniumhq.selenium:htmlunit-driver:2.54.0") { exclude group: "commons-logging", name: "commons-logging" } dependency("org.seleniumhq.selenium:selenium-java:3.141.59") { @@ -292,7 +292,6 @@ configure(allprojects) { project -> repositories { mavenCentral() maven { url "https://repo.spring.io/libs-spring-framework-build" } - } } configurations.all {