From 949432ce8b22c830480fea27ab9d40fe299a5e44 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 3 Dec 2024 13:30:25 +0100 Subject: [PATCH] General upgrade to Jakarta EE 11 APIs Includes removal of ManagedBean and javax.annotation legacy support. Includes AbstractJson(Http)MessageConverter revision for Yasson 3.0. Includes initial Hibernate ORM 7.0 upgrade. Closes gh-34011 Closes gh-33750 --- .../pages/core/beans/classpath-scanning.adoc | 4 +- .../modules/ROOT/pages/integration/email.adoc | 4 +- .../integration-junit-jupiter.adoc | 6 +- framework-platform/framework-platform.gradle | 38 +- integration-tests/integration-tests.gradle | 2 +- spring-beans/spring-beans.gradle | 1 - .../AutowiredAnnotationBeanPostProcessor.java | 15 +- .../JakartaAnnotationsRuntimeHints.java | 6 +- ...erAnnotationAutowireCandidateResolver.java | 13 +- .../factory/support/RootBeanDefinition.java | 4 +- .../JakartaAnnotationsRuntimeHintsTests.java | 10 - .../CandidateComponentsIndexerTests.java | 7 - .../index/sample/cdi/SampleManagedBean.java | 28 - .../spring-context-support.gradle | 2 +- spring-context/spring-context.gradle | 2 - .../AnnotationBeanNameGenerator.java | 14 +- .../annotation/AnnotationConfigUtils.java | 6 +- .../ClassPathBeanDefinitionScanner.java | 5 +- ...athScanningCandidateComponentProvider.java | 31 +- .../CommonAnnotationBeanPostProcessor.java | 91 -- .../IndexedJakartaManagedBeanComponent.java | 24 - .../IndexedJavaxManagedBeanComponent.java | 24 - .../indexed/IndexedJavaxNamedComponent.java | 24 - .../JakartaManagedBeanComponent.java | 24 - .../scannable/JavaxManagedBeanComponent.java | 24 - .../scannable/JavaxNamedComponent.java | 24 - .../InjectAnnotationAutowireContextTests.java | 56 +- .../AnnotationBeanNameGeneratorTests.java | 18 - ...anningCandidateComponentProviderTests.java | 42 +- ...ommonAnnotationBeanPostProcessorTests.java | 131 -- .../example/scannable/spring.components | 5 - .../AbstractJsonMessageConverter.java | 8 +- .../converter/GsonMessageConverter.java | 6 +- ...tlinSerializationJsonMessageConverter.java | 13 +- spring-orm/spring-orm.gradle | 2 +- ...ernateObjectRetrievalFailureException.java | 22 +- .../orm/hibernate5/HibernateOperations.java | 857 ------------ ...nateOptimisticLockingFailureException.java | 4 +- .../orm/hibernate5/HibernateTemplate.java | 1185 ----------------- .../hibernate5/LocalSessionFactoryBean.java | 8 +- .../LocalSessionFactoryBuilder.java | 9 +- .../orm/hibernate5/SessionFactoryUtils.java | 18 +- .../support/HibernateDaoSupport.java | 139 -- .../orm/jpa/ExtendedEntityManagerCreator.java | 3 +- .../MutablePersistenceUnitInfo.java | 13 + ...agedTypesBeanRegistrationAotProcessor.java | 3 +- .../PersistenceUnitReader.java | 1 + .../jpa/vendor/HibernateJpaVendorAdapter.java | 83 +- ...ontainerEntityManagerFactoryBeanTests.java | 17 +- .../LocalEntityManagerFactoryBeanTests.java | 6 + .../orm/jpa/domain2/package-info.java | 5 +- ...ypesBeanRegistrationAotProcessorTests.java | 10 +- .../PersistenceXmlParsingTests.java | 1 + spring-test/spring-test.gradle | 3 +- .../test/context/TestConstructor.java | 17 +- .../context/support/TestConstructorUtils.java | 14 +- ...terAutowiredConstructorInjectionTests.java | 9 - .../orm/HibernateSessionFlushingTests.java | 13 +- .../hibernate/HibernatePersonRepository.java | 2 +- spring-web/spring-web.gradle | 2 +- .../AbstractJsonHttpMessageConverter.java | 3 +- .../json/GsonHttpMessageConverter.java | 4 +- .../web/jsf/el/SpringBeanFacesELResolver.java | 11 +- .../WebApplicationContextFacesELResolver.java | 11 +- .../web/jsf/MockFacesContext.java | 8 +- 65 files changed, 200 insertions(+), 2995 deletions(-) delete mode 100644 spring-context-indexer/src/test/java/org/springframework/context/index/sample/cdi/SampleManagedBean.java delete mode 100644 spring-context/src/test/java/example/indexed/IndexedJakartaManagedBeanComponent.java delete mode 100644 spring-context/src/test/java/example/indexed/IndexedJavaxManagedBeanComponent.java delete mode 100644 spring-context/src/test/java/example/indexed/IndexedJavaxNamedComponent.java delete mode 100644 spring-context/src/test/java/example/scannable/JakartaManagedBeanComponent.java delete mode 100644 spring-context/src/test/java/example/scannable/JavaxManagedBeanComponent.java delete mode 100644 spring-context/src/test/java/example/scannable/JavaxNamedComponent.java delete mode 100644 spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateOperations.java delete mode 100644 spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTemplate.java delete mode 100644 spring-orm/src/main/java/org/springframework/orm/hibernate5/support/HibernateDaoSupport.java diff --git a/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc b/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc index 8193305116b..611009b73f4 100644 --- a/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc +++ b/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc @@ -674,9 +674,7 @@ By default, the `AnnotationBeanNameGenerator` is used. For Spring xref:core/beans/classpath-scanning.adoc#beans-stereotype-annotations[stereotype annotations], if you supply a name via the annotation's `value` attribute that name will be used as the name in the corresponding bean definition. This convention also applies when the -following JSR-250 and JSR-330 annotations are used instead of Spring stereotype -annotations: `@jakarta.annotation.ManagedBean`, `@javax.annotation.ManagedBean`, -`@jakarta.inject.Named`, and `@javax.inject.Named`. +`@jakarta.inject.Named` annotation is used instead of Spring stereotype annotations. As of Spring Framework 6.1, the name of the annotation attribute that is used to specify the bean name is no longer required to be `value`. Custom stereotype annotations can diff --git a/framework-docs/modules/ROOT/pages/integration/email.adoc b/framework-docs/modules/ROOT/pages/integration/email.adoc index 46493a7de9a..420bc481c9d 100644 --- a/framework-docs/modules/ROOT/pages/integration/email.adoc +++ b/framework-docs/modules/ROOT/pages/integration/email.adoc @@ -11,9 +11,7 @@ Spring Framework's email support: * The https://jakartaee.github.io/mail-api/[Jakarta Mail] library This library is freely available on the web -- for example, in Maven Central as -`com.sun.mail:jakarta.mail`. Please make sure to use the latest 2.x version (which uses -the `jakarta.mail` package namespace) rather than Jakarta Mail 1.6.x (which uses the -`javax.mail` package namespace). +`org.eclipse.angus:angus-mail`. **** The Spring Framework provides a helpful utility library for sending email that shields diff --git a/framework-docs/modules/ROOT/pages/testing/annotations/integration-junit-jupiter.adoc b/framework-docs/modules/ROOT/pages/testing/annotations/integration-junit-jupiter.adoc index d359c708ea7..41b16558e1a 100644 --- a/framework-docs/modules/ROOT/pages/testing/annotations/integration-junit-jupiter.adoc +++ b/framework-docs/modules/ROOT/pages/testing/annotations/integration-junit-jupiter.adoc @@ -171,9 +171,9 @@ the parameters of a test class constructor are autowired from components in the If `@TestConstructor` is not present or meta-present on a test class, the default _test constructor autowire mode_ will be used. See the tip below for details on how to change -the default mode. Note, however, that a local declaration of `@Autowired`, -`@jakarta.inject.Inject`, or `@javax.inject.Inject` on a constructor takes precedence -over both `@TestConstructor` and the default mode. +the default mode. Note, however, that a local declaration of `@Autowired` or +`@jakarta.inject.Inject` on a constructor takes precedence over both `@TestConstructor` +and the default mode. .Changing the default test constructor autowire mode [TIP] diff --git a/framework-platform/framework-platform.gradle b/framework-platform/framework-platform.gradle index 804c6fa58ab..25979bcdf7c 100644 --- a/framework-platform/framework-platform.gradle +++ b/framework-platform/framework-platform.gradle @@ -40,7 +40,6 @@ dependencies { api("com.squareup.okhttp3:mockwebserver:3.14.9") api("com.squareup.okhttp3:okhttp:3.14.9") api("com.sun.activation:jakarta.activation:2.0.1") - api("com.sun.mail:jakarta.mail:2.0.1") api("com.sun.xml.bind:jaxb-core:3.0.2") api("com.sun.xml.bind:jaxb-impl:3.0.2") api("com.sun.xml.bind:jaxb-xjc:3.0.2") @@ -61,32 +60,30 @@ dependencies { api("io.undertow:undertow-servlet:2.3.18.Final") api("io.undertow:undertow-websockets-jsr:2.3.18.Final") api("io.vavr:vavr:0.10.4") - api("jakarta.activation:jakarta.activation-api:2.0.1") - api("jakarta.annotation:jakarta.annotation-api:2.0.0") + api("jakarta.activation:jakarta.activation-api:2.1.3") + api("jakarta.annotation:jakarta.annotation-api:3.0.0") api("jakarta.ejb:jakarta.ejb-api:4.0.1") - api("jakarta.el:jakarta.el-api:4.0.0") - api("jakarta.enterprise.concurrent:jakarta.enterprise.concurrent-api:2.0.0") - api("jakarta.faces:jakarta.faces-api:3.0.0") + api("jakarta.el:jakarta.el-api:6.0.1") + api("jakarta.enterprise.concurrent:jakarta.enterprise.concurrent-api:3.1.1") + api("jakarta.faces:jakarta.faces-api:4.1.2") api("jakarta.inject:jakarta.inject-api:2.0.1") api("jakarta.inject:jakarta.inject-tck:2.0.1") - api("jakarta.interceptor:jakarta.interceptor-api:2.0.0") - api("jakarta.jms:jakarta.jms-api:3.0.0") - api("jakarta.json.bind:jakarta.json.bind-api:2.0.0") - api("jakarta.json:jakarta.json-api:2.0.1") - api("jakarta.mail:jakarta.mail-api:2.0.1") - api("jakarta.persistence:jakarta.persistence-api:3.0.0") - api("jakarta.resource:jakarta.resource-api:2.0.0") + api("jakarta.interceptor:jakarta.interceptor-api:2.2.0") + api("jakarta.jms:jakarta.jms-api:3.1.0") + api("jakarta.json.bind:jakarta.json.bind-api:3.0.1") + api("jakarta.json:jakarta.json-api:2.1.3") + api("jakarta.mail:jakarta.mail-api:2.1.3") + api("jakarta.persistence:jakarta.persistence-api:3.2.0") + api("jakarta.resource:jakarta.resource-api:2.1.0") api("jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:3.0.2") api("jakarta.servlet.jsp:jakarta.servlet.jsp-api:4.0.0") api("jakarta.servlet:jakarta.servlet-api:6.1.0") api("jakarta.transaction:jakarta.transaction-api:2.0.1") - api("jakarta.validation:jakarta.validation-api:3.0.2") + api("jakarta.validation:jakarta.validation-api:3.1.0") api("jakarta.websocket:jakarta.websocket-api:2.2.0") api("jakarta.websocket:jakarta.websocket-client-api:2.2.0") api("jakarta.xml.bind:jakarta.xml.bind-api:3.0.1") - api("javax.annotation:javax.annotation-api:1.3.2") api("javax.cache:cache-api:1.1.1") - api("javax.inject:javax.inject:1") api("javax.money:money-api:1.1") api("jaxen:jaxen:1.2.0") api("junit:junit:4.13.2") @@ -117,9 +114,10 @@ dependencies { api("org.crac:crac:1.4.0") api("org.dom4j:dom4j:2.1.4") api("org.easymock:easymock:5.4.0") + api("org.eclipse.angus:angus-mail:2.0.3") api("org.eclipse.jetty:jetty-reactive-httpclient:4.0.8") - api("org.eclipse.persistence:org.eclipse.persistence.jpa:3.0.4") - api("org.eclipse:yasson:2.0.4") + api("org.eclipse.persistence:org.eclipse.persistence.jpa:5.0.0-B04") + api("org.eclipse:yasson:3.0.4") api("org.ehcache:ehcache:3.10.8") api("org.ehcache:jcache:1.0.1") api("org.freemarker:freemarker:2.3.33") @@ -128,8 +126,8 @@ dependencies { api("org.glassfish.tyrus:tyrus-container-servlet:2.1.3") api("org.graalvm.sdk:graal-sdk:22.3.1") api("org.hamcrest:hamcrest:2.2") - api("org.hibernate:hibernate-core-jakarta:5.6.15.Final") - api("org.hibernate:hibernate-validator:7.0.5.Final") + api("org.hibernate:hibernate-core:7.0.0.Beta2") + api("org.hibernate:hibernate-validator:9.0.0.Beta3") api("org.hsqldb:hsqldb:2.7.4") api("org.htmlunit:htmlunit:4.6.0") api("org.javamoney:moneta:1.4.4") diff --git a/integration-tests/integration-tests.gradle b/integration-tests/integration-tests.gradle index 1444b2bb210..b386be32ddb 100644 --- a/integration-tests/integration-tests.gradle +++ b/integration-tests/integration-tests.gradle @@ -26,7 +26,7 @@ dependencies { testImplementation("jakarta.servlet:jakarta.servlet-api") testImplementation("org.aspectj:aspectjweaver") testImplementation("org.hsqldb:hsqldb") - testImplementation("org.hibernate:hibernate-core-jakarta") + testImplementation("org.hibernate:hibernate-core") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") } diff --git a/spring-beans/spring-beans.gradle b/spring-beans/spring-beans.gradle index c4fb10eb320..b407bf0ed24 100644 --- a/spring-beans/spring-beans.gradle +++ b/spring-beans/spring-beans.gradle @@ -16,5 +16,4 @@ dependencies { testImplementation(project(":spring-core-test")) testImplementation(testFixtures(project(":spring-core"))) testImplementation("jakarta.annotation:jakarta.annotation-api") - testImplementation("javax.inject:javax.inject") } 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 d0ba827163e..c187dccf97e 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 @@ -103,8 +103,6 @@ import org.springframework.util.StringUtils; * *

Also supports the common {@link jakarta.inject.Inject @Inject} annotation, * if available, as a direct alternative to Spring's own {@code @Autowired}. - * Additionally, it retains support for the {@code javax.inject.Inject} variant - * dating back to the original JSR-330 specification (as known from Java EE 6-8). * *

Autowired Constructors

*

Only one constructor of any given bean class may declare this annotation with @@ -189,8 +187,8 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA /** * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's * standard {@link Autowired @Autowired} and {@link Value @Value} annotations. - *

Also supports the common {@link jakarta.inject.Inject @Inject} annotation, - * if available, as well as the original {@code javax.inject.Inject} variant. + *

Also supports the common {@link jakarta.inject.Inject @Inject} annotation + * if available. */ @SuppressWarnings("unchecked") public AutowiredAnnotationBeanPostProcessor() { @@ -206,15 +204,6 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA catch (ClassNotFoundException ex) { // jakarta.inject API not available - simply skip. } - - try { - this.autowiredAnnotationTypes.add((Class) - ClassUtils.forName("javax.inject.Inject", classLoader)); - logger.trace("'javax.inject.Inject' annotation found and supported for autowiring"); - } - catch (ClassNotFoundException ex) { - // javax.inject API not available - simply skip. - } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java index 439b1fb30e4..c4ad0a257da 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java @@ -33,14 +33,10 @@ class JakartaAnnotationsRuntimeHints implements RuntimeHintsRegistrar { @Override public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) { - // javax.inject.Provider is omitted from the list, since we do not currently load - // it via reflection. Stream.of( "jakarta.inject.Inject", "jakarta.inject.Provider", - "jakarta.inject.Qualifier", - "javax.inject.Inject", - "javax.inject.Qualifier" + "jakarta.inject.Qualifier" ).forEach(typeName -> hints.reflection().registerType(TypeReference.of(typeName))); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java index 4281e653949..1e086230061 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java @@ -47,8 +47,7 @@ import org.springframework.util.ObjectUtils; * against {@link Qualifier qualifier annotations} on the field or parameter to be autowired. * Also supports suggested expression values through a {@link Value value} annotation. * - *

Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation (as well as its - * pre-Jakarta {@code javax.inject.Qualifier} equivalent), if available. + *

Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation if available. * * @author Mark Fisher * @author Juergen Hoeller @@ -69,8 +68,7 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa /** * Create a new {@code QualifierAnnotationAutowireCandidateResolver} for Spring's * standard {@link Qualifier} annotation. - *

Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation (as well as - * its pre-Jakarta {@code javax.inject.Qualifier} equivalent), if available. + *

Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation if available. */ @SuppressWarnings("unchecked") public QualifierAnnotationAutowireCandidateResolver() { @@ -82,13 +80,6 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa catch (ClassNotFoundException ex) { // JSR-330 API (as included in Jakarta EE) not available - simply skip. } - try { - this.qualifierTypes.add((Class) ClassUtils.forName("javax.inject.Qualifier", - QualifierAnnotationAutowireCandidateResolver.class.getClassLoader())); - } - catch (ClassNotFoundException ex) { - // JSR-330 API not available - simply skip. - } } /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java index 67aad00a312..5f91f6bdcee 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java @@ -508,8 +508,8 @@ public class RootBeanDefinition extends AbstractBeanDefinition { /** * Register an externally managed configuration initialization method — - * for example, a method annotated with JSR-250's {@code javax.annotation.PostConstruct} - * or Jakarta's {@link jakarta.annotation.PostConstruct} annotation. + * for example, a method annotated with Jakarta's + * {@link jakarta.annotation.PostConstruct} annotation. *

The supplied {@code initMethod} may be a * {@linkplain Method#getName() simple method name} or a * {@linkplain org.springframework.util.ClassUtils#getQualifiedMethodName(Method) diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java index ef2e236fb68..371e93013d4 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java @@ -63,14 +63,4 @@ class JakartaAnnotationsRuntimeHintsTests { assertThat(RuntimeHintsPredicates.reflection().onType(Qualifier.class)).accepts(this.hints); } - @Test // gh-33345 - void javaxInjectAnnotationHasHints() { - assertThat(RuntimeHintsPredicates.reflection().onType(javax.inject.Inject.class)).accepts(this.hints); - } - - @Test // gh-33345 - void javaxQualifierAnnotationHasHints() { - assertThat(RuntimeHintsPredicates.reflection().onType(javax.inject.Qualifier.class)).accepts(this.hints); - } - } diff --git a/spring-context-indexer/src/test/java/org/springframework/context/index/processor/CandidateComponentsIndexerTests.java b/spring-context-indexer/src/test/java/org/springframework/context/index/processor/CandidateComponentsIndexerTests.java index 99508148837..531782f4043 100644 --- a/spring-context-indexer/src/test/java/org/springframework/context/index/processor/CandidateComponentsIndexerTests.java +++ b/spring-context-indexer/src/test/java/org/springframework/context/index/processor/CandidateComponentsIndexerTests.java @@ -21,7 +21,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Path; -import jakarta.annotation.ManagedBean; import jakarta.inject.Named; import jakarta.persistence.Converter; import jakarta.persistence.Embeddable; @@ -43,7 +42,6 @@ import org.springframework.context.index.sample.SampleNonStaticEmbedded; import org.springframework.context.index.sample.SampleNone; import org.springframework.context.index.sample.SampleRepository; import org.springframework.context.index.sample.SampleService; -import org.springframework.context.index.sample.cdi.SampleManagedBean; import org.springframework.context.index.sample.cdi.SampleNamed; import org.springframework.context.index.sample.cdi.SampleTransactional; import org.springframework.context.index.sample.jpa.SampleConverter; @@ -126,11 +124,6 @@ class CandidateComponentsIndexerTests { testComponent(AbstractController.class); } - @Test - void cdiManagedBean() { - testSingleComponent(SampleManagedBean.class, ManagedBean.class); - } - @Test void cdiNamed() { testSingleComponent(SampleNamed.class, Named.class); diff --git a/spring-context-indexer/src/test/java/org/springframework/context/index/sample/cdi/SampleManagedBean.java b/spring-context-indexer/src/test/java/org/springframework/context/index/sample/cdi/SampleManagedBean.java deleted file mode 100644 index fb34361664d..00000000000 --- a/spring-context-indexer/src/test/java/org/springframework/context/index/sample/cdi/SampleManagedBean.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2002-2016 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 - * - * https://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.context.index.sample.cdi; - -import jakarta.annotation.ManagedBean; - -/** - * Test candidate for a CDI {@link ManagedBean}. - * - * @author Stephane Nicoll - */ -@ManagedBean -public class SampleManagedBean { -} diff --git a/spring-context-support/spring-context-support.gradle b/spring-context-support/spring-context-support.gradle index a2f0c083e73..851125b73e5 100644 --- a/spring-context-support/spring-context-support.gradle +++ b/spring-context-support/spring-context-support.gradle @@ -23,7 +23,7 @@ dependencies { testImplementation("io.projectreactor:reactor-core") testImplementation("jakarta.annotation:jakarta.annotation-api") testImplementation("org.hsqldb:hsqldb") - testRuntimeOnly("com.sun.mail:jakarta.mail") + testRuntimeOnly("org.eclipse.angus:angus-mail") testRuntimeOnly("org.ehcache:ehcache") testRuntimeOnly("org.ehcache:jcache") testRuntimeOnly("org.glassfish:jakarta.el") diff --git a/spring-context/spring-context.gradle b/spring-context/spring-context.gradle index af48a0fa207..4a24c9ac41c 100644 --- a/spring-context/spring-context.gradle +++ b/spring-context/spring-context.gradle @@ -21,8 +21,6 @@ dependencies { optional("jakarta.inject:jakarta.inject-api") optional("jakarta.interceptor:jakarta.interceptor-api") optional("jakarta.validation:jakarta.validation-api") - optional("javax.annotation:javax.annotation-api") - optional("javax.inject:javax.inject") optional("javax.money:money-api") optional("org.apache.groovy:groovy") optional("org.apache-extras.beanshell:bsh") diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationBeanNameGenerator.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationBeanNameGenerator.java index 3361f0560e5..d8bb37df83f 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationBeanNameGenerator.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationBeanNameGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -51,11 +51,8 @@ import org.springframework.util.StringUtils; * {@link org.springframework.stereotype.Repository @Repository}) are * themselves annotated with {@code @Component}. * - *

Also supports Jakarta EE's {@link jakarta.annotation.ManagedBean} and - * JSR-330's {@link jakarta.inject.Named} annotations (as well as their pre-Jakarta - * {@code javax.annotation.ManagedBean} and {@code javax.inject.Named} equivalents), - * if available. Note that Spring component annotations always override such - * standard annotations. + *

Also supports JSR-330's {@link jakarta.inject.Named} annotation if available. + * Note that Spring component annotations always override such standard annotations. * *

If the annotation's value doesn't indicate a bean name, an appropriate * name will be built based on the short name of the class (with the first @@ -219,10 +216,7 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator { Set metaAnnotationTypes, Map attributes) { boolean isStereotype = metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME) || - annotationType.equals("jakarta.annotation.ManagedBean") || - annotationType.equals("javax.annotation.ManagedBean") || - annotationType.equals("jakarta.inject.Named") || - annotationType.equals("javax.inject.Named"); + annotationType.equals("jakarta.inject.Named"); return (isStereotype && attributes.containsKey("value")); } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java index e427aaf5b85..540515fdf21 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java @@ -117,9 +117,6 @@ public abstract class AnnotationConfigUtils { private static final boolean jakartaAnnotationsPresent = ClassUtils.isPresent("jakarta.annotation.PostConstruct", classLoader); - private static final boolean jsr250Present = - ClassUtils.isPresent("javax.annotation.PostConstruct", classLoader); - private static final boolean jpaPresent = ClassUtils.isPresent("jakarta.persistence.EntityManagerFactory", classLoader) && ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, classLoader); @@ -169,8 +166,7 @@ public abstract class AnnotationConfigUtils { } // Check for Jakarta Annotations support, and if present add the CommonAnnotationBeanPostProcessor. - if ((jakartaAnnotationsPresent || jsr250Present) && - !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { + if (jakartaAnnotationsPresent && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java index a68de8cacb9..bee5d806d15 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -48,8 +48,7 @@ import org.springframework.util.PatternMatchUtils; * {@link org.springframework.stereotype.Service @Service}, or * {@link org.springframework.stereotype.Controller @Controller} stereotype. * - *

Also supports Jakarta EE's {@link jakarta.annotation.ManagedBean} and - * JSR-330's {@link jakarta.inject.Named} annotations, if available. + *

Also supports JSR-330's {@link jakarta.inject.Named} annotations, if available. * * @author Mark Fisher * @author Juergen Hoeller diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java index daeb1cd833e..6016fcf6556 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -216,31 +216,12 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC * {@link Component @Component} meta-annotation including the * {@link Repository @Repository}, {@link Service @Service}, and * {@link Controller @Controller} stereotype annotations. - *

Also supports Jakarta EE's {@link jakarta.annotation.ManagedBean} and - * JSR-330's {@link jakarta.inject.Named} annotations (as well as their - * pre-Jakarta {@code javax.annotation.ManagedBean} and {@code javax.inject.Named} - * equivalents), if available. + *

Also supports JSR-330's {@link jakarta.inject.Named} annotation if available. */ @SuppressWarnings("unchecked") protected void registerDefaultFilters() { this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); - try { - this.includeFilters.add(new AnnotationTypeFilter( - ((Class) ClassUtils.forName("jakarta.annotation.ManagedBean", cl)), false)); - logger.trace("JSR-250 'jakarta.annotation.ManagedBean' found and supported for component scanning"); - } - catch (ClassNotFoundException ex) { - // JSR-250 1.1 API (as included in Jakarta EE) not available - simply skip. - } - try { - this.includeFilters.add(new AnnotationTypeFilter( - ((Class) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false)); - logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning"); - } - catch (ClassNotFoundException ex) { - // JSR-250 1.1 API not available - simply skip. - } try { this.includeFilters.add(new AnnotationTypeFilter( ((Class) ClassUtils.forName("jakarta.inject.Named", cl)), false)); @@ -249,14 +230,6 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC catch (ClassNotFoundException ex) { // JSR-330 API (as included in Jakarta EE) not available - simply skip. } - try { - this.includeFilters.add(new AnnotationTypeFilter( - ((Class) ClassUtils.forName("javax.inject.Named", cl)), false)); - logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning"); - } - catch (ClassNotFoundException ex) { - // JSR-330 API not available - simply skip. - } } /** 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 a5ffc7858f8..7e65b98cdbf 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 @@ -96,11 +96,6 @@ import org.springframework.util.StringValueResolver; * and default names as well. The target beans can be simple POJOs, with no special * requirements other than the type having to match. * - *

Additionally, the original {@code javax.annotation} variants of the annotations - * dating back to the JSR-250 specification (Java EE 5-8, also included in JDK 6-8) - * are still supported as well. Note that this is primarily for a smooth upgrade path, - * not for adoption in new applications. - * *

This post-processor also supports the EJB {@link jakarta.ejb.EJB} annotation, * analogous to {@link jakarta.annotation.Resource}, with the capability to * specify both a local bean name and a global JNDI name for fallback retrieval. @@ -154,9 +149,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean @Nullable private static final Class jakartaResourceType; - @Nullable - private static final Class javaxResourceType; - @Nullable private static final Class ejbAnnotationType; @@ -166,11 +158,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean resourceAnnotationTypes.add(jakartaResourceType); } - javaxResourceType = loadAnnotationType("javax.annotation.Resource"); - if (javaxResourceType != null) { - resourceAnnotationTypes.add(javaxResourceType); - } - ejbAnnotationType = loadAnnotationType("jakarta.ejb.EJB"); if (ejbAnnotationType != null) { resourceAnnotationTypes.add(ejbAnnotationType); @@ -212,10 +199,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean addInitAnnotationType(loadAnnotationType("jakarta.annotation.PostConstruct")); addDestroyAnnotationType(loadAnnotationType("jakarta.annotation.PreDestroy")); - // Tolerate legacy JSR-250 annotations in javax.annotation package - addInitAnnotationType(loadAnnotationType("javax.annotation.PostConstruct")); - addDestroyAnnotationType(loadAnnotationType("javax.annotation.PreDestroy")); - // java.naming module present on JDK 9+? if (jndiPresent) { this.jndiFactory = new SimpleJndiBeanFactory(); @@ -444,14 +427,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean currElements.add(new ResourceElement(field, field, null)); } } - else if (javaxResourceType != null && field.isAnnotationPresent(javaxResourceType)) { - if (Modifier.isStatic(field.getModifiers())) { - throw new IllegalStateException("@Resource annotation is not supported on static fields"); - } - if (!this.ignoredResourceTypes.contains(field.getType().getName())) { - currElements.add(new LegacyResourceElement(field, field, null)); - } - } }); ReflectionUtils.doWithLocalMethods(targetClass, method -> { @@ -486,21 +461,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean } } } - else if (javaxResourceType != null && bridgedMethod.isAnnotationPresent(javaxResourceType)) { - if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { - if (Modifier.isStatic(method.getModifiers())) { - throw new IllegalStateException("@Resource annotation is not supported on static methods"); - } - Class[] paramTypes = method.getParameterTypes(); - if (paramTypes.length != 1) { - throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method); - } - if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) { - PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); - currElements.add(new LegacyResourceElement(method, bridgedMethod, pd)); - } - } - } }); elements.addAll(0, currElements); @@ -746,57 +706,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean } - /** - * Class representing injection information about an annotated field - * or setter method, supporting the @Resource annotation. - */ - private class LegacyResourceElement extends LookupElement { - - private final boolean lazyLookup; - - public LegacyResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) { - super(member, pd); - javax.annotation.Resource resource = ae.getAnnotation(javax.annotation.Resource.class); - String resourceName = resource.name(); - Class resourceType = resource.type(); - this.isDefaultName = !StringUtils.hasLength(resourceName); - if (this.isDefaultName) { - resourceName = this.member.getName(); - if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) { - resourceName = StringUtils.uncapitalizeAsProperty(resourceName.substring(3)); - } - } - else if (embeddedValueResolver != null) { - resourceName = embeddedValueResolver.resolveStringValue(resourceName); - } - if (Object.class != resourceType) { - checkResourceType(resourceType); - } - else { - // No resource type specified... check field/method. - resourceType = getResourceType(); - } - this.name = (resourceName != null ? resourceName : ""); - this.lookupType = resourceType; - String lookupValue = resource.lookup(); - this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName()); - Lazy lazy = ae.getAnnotation(Lazy.class); - this.lazyLookup = (lazy != null && lazy.value()); - } - - @Override - protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) { - return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) : - getResource(this, requestingBeanName)); - } - - @Override - boolean isLazyLookup() { - return this.lazyLookup; - } - } - - /** * Class representing injection information about an annotated field * or setter method, supporting the @EJB annotation. diff --git a/spring-context/src/test/java/example/indexed/IndexedJakartaManagedBeanComponent.java b/spring-context/src/test/java/example/indexed/IndexedJakartaManagedBeanComponent.java deleted file mode 100644 index ed640a7a73d..00000000000 --- a/spring-context/src/test/java/example/indexed/IndexedJakartaManagedBeanComponent.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://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 example.indexed; - -/** - * @author Sam Brannen - */ -@jakarta.annotation.ManagedBean -public class IndexedJakartaManagedBeanComponent { -} diff --git a/spring-context/src/test/java/example/indexed/IndexedJavaxManagedBeanComponent.java b/spring-context/src/test/java/example/indexed/IndexedJavaxManagedBeanComponent.java deleted file mode 100644 index b563b4d3797..00000000000 --- a/spring-context/src/test/java/example/indexed/IndexedJavaxManagedBeanComponent.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2002-2023 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 - * - * https://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 example.indexed; - -/** - * @author Sam Brannen - */ -@javax.annotation.ManagedBean -public class IndexedJavaxManagedBeanComponent { -} diff --git a/spring-context/src/test/java/example/indexed/IndexedJavaxNamedComponent.java b/spring-context/src/test/java/example/indexed/IndexedJavaxNamedComponent.java deleted file mode 100644 index 581be8a6f97..00000000000 --- a/spring-context/src/test/java/example/indexed/IndexedJavaxNamedComponent.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2002-2023 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 - * - * https://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 example.indexed; - -/** - * @author Sam Brannen - */ -@javax.inject.Named("myIndexedJavaxNamedComponent") -public class IndexedJavaxNamedComponent { -} diff --git a/spring-context/src/test/java/example/scannable/JakartaManagedBeanComponent.java b/spring-context/src/test/java/example/scannable/JakartaManagedBeanComponent.java deleted file mode 100644 index 6140ea0dce3..00000000000 --- a/spring-context/src/test/java/example/scannable/JakartaManagedBeanComponent.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2002-2023 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 - * - * https://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 example.scannable; - -/** - * @author Sam Brannen - */ -@jakarta.annotation.ManagedBean("myJakartaManagedBeanComponent") -public class JakartaManagedBeanComponent { -} diff --git a/spring-context/src/test/java/example/scannable/JavaxManagedBeanComponent.java b/spring-context/src/test/java/example/scannable/JavaxManagedBeanComponent.java deleted file mode 100644 index b3029035d87..00000000000 --- a/spring-context/src/test/java/example/scannable/JavaxManagedBeanComponent.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2002-2023 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 - * - * https://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 example.scannable; - -/** - * @author Sam Brannen - */ -@javax.annotation.ManagedBean("myJavaxManagedBeanComponent") -public class JavaxManagedBeanComponent { -} diff --git a/spring-context/src/test/java/example/scannable/JavaxNamedComponent.java b/spring-context/src/test/java/example/scannable/JavaxNamedComponent.java deleted file mode 100644 index a0fe78e7429..00000000000 --- a/spring-context/src/test/java/example/scannable/JavaxNamedComponent.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2002-2023 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 - * - * https://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 example.scannable; - -/** - * @author Sam Brannen - */ -@javax.inject.Named("myJavaxNamedComponent") -public class JavaxNamedComponent { -} diff --git a/spring-context/src/test/java/org/springframework/beans/factory/support/InjectAnnotationAutowireContextTests.java b/spring-context/src/test/java/org/springframework/beans/factory/support/InjectAnnotationAutowireContextTests.java index 48d19fbf7e8..bfbcbb09677 100644 --- a/spring-context/src/test/java/org/springframework/beans/factory/support/InjectAnnotationAutowireContextTests.java +++ b/spring-context/src/test/java/org/springframework/beans/factory/support/InjectAnnotationAutowireContextTests.java @@ -40,8 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** - * Integration tests for handling JSR-330 {@link jakarta.inject.Qualifier} and - * {@link javax.inject.Qualifier} annotations. + * Integration tests for handling {@link jakarta.inject.Qualifier} annotations. * * @author Juergen Hoeller * @author Sam Brannen @@ -317,16 +316,6 @@ class InjectAnnotationAutowireContextTests { assertThat(bean.getAnimal2().getName()).isEqualTo("Jakarta Fido"); } - @Test // gh-33345 - void autowiredConstructorArgumentResolvesJavaxNamedCandidate() { - Class testBeanClass = JavaxNamedConstructorArgumentTestBean.class; - AnnotationConfigApplicationContext context = - new AnnotationConfigApplicationContext(testBeanClass, JavaxCat.class, JavaxDog.class); - JavaxNamedConstructorArgumentTestBean bean = context.getBean(testBeanClass); - assertThat(bean.getAnimal1().getName()).isEqualTo("Javax Tiger"); - assertThat(bean.getAnimal2().getName()).isEqualTo("Javax Fido"); - } - @Test void autowiredFieldResolvesQualifiedCandidateWithDefaultValueAndNoValueOnBeanDefinition() { GenericApplicationContext context = new GenericApplicationContext(); @@ -587,29 +576,6 @@ class InjectAnnotationAutowireContextTests { } - static class JavaxNamedConstructorArgumentTestBean { - - private final Animal animal1; - private final Animal animal2; - - @javax.inject.Inject - public JavaxNamedConstructorArgumentTestBean(@javax.inject.Named("Cat") Animal animal1, - @javax.inject.Named("Dog") Animal animal2) { - - this.animal1 = animal1; - this.animal2 = animal2; - } - - public Animal getAnimal1() { - return this.animal1; - } - - public Animal getAnimal2() { - return this.animal2; - } - } - - public static class QualifiedFieldWithDefaultValueTestBean { @Inject @@ -705,16 +671,6 @@ class InjectAnnotationAutowireContextTests { } - @javax.inject.Named("Cat") - static class JavaxCat implements Animal { - - @Override - public String getName() { - return "Javax Tiger"; - } - } - - @jakarta.inject.Named("Dog") static class JakartaDog implements Animal { @@ -725,16 +681,6 @@ class InjectAnnotationAutowireContextTests { } - @javax.inject.Named("Dog") - static class JavaxDog implements Animal { - - @Override - public String getName() { - return "Javax Fido"; - } - } - - @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier diff --git a/spring-context/src/test/java/org/springframework/context/annotation/AnnotationBeanNameGeneratorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/AnnotationBeanNameGeneratorTests.java index 884bc07d786..8af7c9a322c 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/AnnotationBeanNameGeneratorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/AnnotationBeanNameGeneratorTests.java @@ -23,10 +23,7 @@ import java.lang.annotation.Target; import java.util.List; import example.scannable.DefaultNamedComponent; -import example.scannable.JakartaManagedBeanComponent; import example.scannable.JakartaNamedComponent; -import example.scannable.JavaxManagedBeanComponent; -import example.scannable.JavaxNamedComponent; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; @@ -108,21 +105,6 @@ class AnnotationBeanNameGeneratorTests { assertGeneratedName(JakartaNamedComponent.class, "myJakartaNamedComponent"); } - @Test - void generateBeanNameWithJavaxNamedComponent() { - assertGeneratedName(JavaxNamedComponent.class, "myJavaxNamedComponent"); - } - - @Test - void generateBeanNameWithJakartaManagedBeanComponent() { - assertGeneratedName(JakartaManagedBeanComponent.class, "myJakartaManagedBeanComponent"); - } - - @Test - void generateBeanNameWithJavaxManagedBeanComponent() { - assertGeneratedName(JavaxManagedBeanComponent.class, "myJavaxManagedBeanComponent"); - } - @Test void generateBeanNameWithCustomStereotypeComponent() { assertGeneratedName(DefaultNamedComponent.class, "thoreau"); diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java index f7880f4910d..48c6f6db728 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -27,10 +27,7 @@ import java.util.regex.Pattern; import java.util.stream.Stream; import example.gh24375.AnnotatedComponent; -import example.indexed.IndexedJakartaManagedBeanComponent; import example.indexed.IndexedJakartaNamedComponent; -import example.indexed.IndexedJavaxManagedBeanComponent; -import example.indexed.IndexedJavaxNamedComponent; import example.profilescan.DevComponent; import example.profilescan.ProfileAnnotatedComponent; import example.profilescan.ProfileMetaAnnotatedComponent; @@ -40,10 +37,7 @@ import example.scannable.DefaultNamedComponent; import example.scannable.FooDao; import example.scannable.FooService; import example.scannable.FooServiceImpl; -import example.scannable.JakartaManagedBeanComponent; import example.scannable.JakartaNamedComponent; -import example.scannable.JavaxManagedBeanComponent; -import example.scannable.JavaxNamedComponent; import example.scannable.MessageBean; import example.scannable.NamedComponent; import example.scannable.NamedStubDao; @@ -99,51 +93,31 @@ class ClassPathScanningCandidateComponentProviderTests { BarComponent.class ); - private static final Set> scannedJakartaComponents = Set.of( - JakartaNamedComponent.class, - JakartaManagedBeanComponent.class - ); - - private static final Set> scannedJavaxComponents = Set.of( - JavaxNamedComponent.class, - JavaxManagedBeanComponent.class - ); - - private static final Set> indexedComponents = Set.of( - IndexedJakartaNamedComponent.class, - IndexedJakartaManagedBeanComponent.class, - IndexedJavaxNamedComponent.class, - IndexedJavaxManagedBeanComponent.class - ); - @Test void defaultsWithScan() { ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true); provider.setResourceLoader(new DefaultResourceLoader( CandidateComponentsTestClassLoader.disableIndex(getClass().getClassLoader()))); - testDefault(provider, TEST_BASE_PACKAGE, true, true, false); + testDefault(provider, TEST_BASE_PACKAGE, true, false); } @Test void defaultsWithIndex() { ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true); provider.setResourceLoader(new DefaultResourceLoader(TEST_BASE_CLASSLOADER)); - testDefault(provider, "example", true, true, true); + testDefault(provider, "example", true, true); } private void testDefault(ClassPathScanningCandidateComponentProvider provider, String basePackage, - boolean includeScannedJakartaComponents, boolean includeScannedJavaxComponents, boolean includeIndexedComponents) { + boolean includeScannedJakartaComponents, boolean includeIndexedComponents) { Set> expectedTypes = new HashSet<>(springComponents); if (includeScannedJakartaComponents) { - expectedTypes.addAll(scannedJakartaComponents); - } - if (includeScannedJavaxComponents) { - expectedTypes.addAll(scannedJavaxComponents); + expectedTypes.add(JakartaNamedComponent.class); } if (includeIndexedComponents) { - expectedTypes.addAll(indexedComponents); + expectedTypes.add(IndexedJakartaNamedComponent.class); } Set candidates = provider.findCandidateComponents(basePackage); @@ -216,7 +190,7 @@ class ClassPathScanningCandidateComponentProviderTests { private void testCustomAnnotationTypeIncludeFilter(ClassPathScanningCandidateComponentProvider provider) { provider.addIncludeFilter(new AnnotationTypeFilter(Component.class)); - testDefault(provider, TEST_BASE_PACKAGE, false, false, false); + testDefault(provider, TEST_BASE_PACKAGE, false, false); } @Test @@ -309,7 +283,7 @@ class ClassPathScanningCandidateComponentProviderTests { Set candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE); assertScannedBeanDefinitions(candidates); assertBeanTypes(candidates, FooServiceImpl.class, StubFooDao.class, ServiceInvocationCounter.class, - BarComponent.class, JakartaManagedBeanComponent.class, JavaxManagedBeanComponent.class); + BarComponent.class); } @Test diff --git a/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java index b08c67573eb..170d26dcf3d 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java @@ -116,16 +116,6 @@ class CommonAnnotationBeanPostProcessorTests { assertThat(bean.destroyCalled).isTrue(); } - @Test - void postConstructAndPreDestroyWithLegacyAnnotations() { - bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(LegacyAnnotatedInitDestroyBean.class)); - - LegacyAnnotatedInitDestroyBean bean = (LegacyAnnotatedInitDestroyBean) bf.getBean("annotatedBean"); - assertThat(bean.initCalled).isTrue(); - bf.destroySingletons(); - assertThat(bean.destroyCalled).isTrue(); - } - @Test void postConstructAndPreDestroyWithManualConfiguration() { InitDestroyAnnotationBeanPostProcessor bpp = new InitDestroyAnnotationBeanPostProcessor(); @@ -223,26 +213,6 @@ class CommonAnnotationBeanPostProcessorTests { assertThat(bean.destroy3Called).isTrue(); } - @Test - void resourceInjectionWithLegacyAnnotations() { - bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(LegacyResourceInjectionBean.class)); - TestBean tb = new TestBean(); - bf.registerSingleton("testBean", tb); - TestBean tb2 = new TestBean(); - bf.registerSingleton("testBean2", tb2); - - LegacyResourceInjectionBean bean = (LegacyResourceInjectionBean) bf.getBean("annotatedBean"); - assertThat(bean.initCalled).isTrue(); - assertThat(bean.init2Called).isTrue(); - assertThat(bean.init3Called).isTrue(); - assertThat(bean.getTestBean()).isSameAs(tb); - assertThat(bean.getTestBean2()).isSameAs(tb2); - bf.destroySingletons(); - assertThat(bean.destroyCalled).isTrue(); - assertThat(bean.destroy2Called).isTrue(); - assertThat(bean.destroy3Called).isTrue(); - } - @Test void resourceInjectionWithResolvableDependencyType() { bpp.setBeanFactory(bf); @@ -558,30 +528,6 @@ class CommonAnnotationBeanPostProcessorTests { } - public static class LegacyAnnotatedInitDestroyBean { - - public boolean initCalled = false; - - public boolean destroyCalled = false; - - @javax.annotation.PostConstruct - private void init() { - if (this.initCalled) { - throw new IllegalStateException("Already called"); - } - this.initCalled = true; - } - - @javax.annotation.PreDestroy - private void destroy() { - if (this.destroyCalled) { - throw new IllegalStateException("Already called"); - } - this.destroyCalled = true; - } - } - - public static class InitDestroyBeanPostProcessor implements DestructionAwareBeanPostProcessor { @Override @@ -691,83 +637,6 @@ class CommonAnnotationBeanPostProcessorTests { } - public static class LegacyResourceInjectionBean extends LegacyAnnotatedInitDestroyBean { - - public boolean init2Called = false; - - public boolean init3Called = false; - - public boolean destroy2Called = false; - - public boolean destroy3Called = false; - - @javax.annotation.Resource - private TestBean testBean; - - private TestBean testBean2; - - @javax.annotation.PostConstruct - protected void init2() { - if (this.testBean == null || this.testBean2 == null) { - throw new IllegalStateException("Resources not injected"); - } - if (!this.initCalled) { - throw new IllegalStateException("Superclass init method not called yet"); - } - if (this.init2Called) { - throw new IllegalStateException("Already called"); - } - this.init2Called = true; - } - - @javax.annotation.PostConstruct - private void init() { - if (this.init3Called) { - throw new IllegalStateException("Already called"); - } - this.init3Called = true; - } - - @javax.annotation.PreDestroy - protected void destroy2() { - if (this.destroyCalled) { - throw new IllegalStateException("Superclass destroy called too soon"); - } - if (this.destroy2Called) { - throw new IllegalStateException("Already called"); - } - this.destroy2Called = true; - } - - @javax.annotation.PreDestroy - private void destroy() { - if (this.destroyCalled) { - throw new IllegalStateException("Superclass destroy called too soon"); - } - if (this.destroy3Called) { - throw new IllegalStateException("Already called"); - } - this.destroy3Called = true; - } - - @javax.annotation.Resource - public void setTestBean2(TestBean testBean2) { - if (this.testBean2 != null) { - throw new IllegalStateException("Already called"); - } - this.testBean2 = testBean2; - } - - public TestBean getTestBean() { - return testBean; - } - - public TestBean getTestBean2() { - return testBean2; - } - } - - static class NonPublicResourceInjectionBean extends ResourceInjectionBean { @Resource(name="testBean4", type=TestBean.class) diff --git a/spring-context/src/test/resources/example/scannable/spring.components b/spring-context/src/test/resources/example/scannable/spring.components index 3fdf592b196..8c298cd44d9 100644 --- a/spring-context/src/test/resources/example/scannable/spring.components +++ b/spring-context/src/test/resources/example/scannable/spring.components @@ -10,9 +10,4 @@ example.scannable.ServiceInvocationCounter=org.springframework.stereotype.Compon example.scannable.sub.BarComponent=org.springframework.stereotype.Component example.scannable.JakartaManagedBeanComponent=jakarta.annotation.ManagedBean example.scannable.JakartaNamedComponent=jakarta.inject.Named -example.scannable.JavaxManagedBeanComponent=javax.annotation.ManagedBean -example.scannable.JavaxNamedComponent=javax.inject.Named -example.indexed.IndexedJakartaManagedBeanComponent=jakarta.annotation.ManagedBean example.indexed.IndexedJakartaNamedComponent=jakarta.inject.Named -example.indexed.IndexedJavaxManagedBeanComponent=javax.annotation.ManagedBean -example.indexed.IndexedJavaxNamedComponent=javax.inject.Named diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractJsonMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractJsonMessageConverter.java index d3032dc5ad0..a73dccd77ba 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractJsonMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractJsonMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -18,6 +18,7 @@ package org.springframework.messaging.converter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; @@ -91,7 +92,6 @@ public abstract class AbstractJsonMessageConverter extends AbstractMessageConver ByteArrayOutputStream out = new ByteArrayOutputStream(1024); Writer writer = getWriter(out, headers); toJson(payload, resolvedType, writer); - writer.flush(); return out.toByteArray(); } else { @@ -120,11 +120,11 @@ public abstract class AbstractJsonMessageConverter extends AbstractMessageConver } - protected abstract Object fromJson(Reader reader, Type resolvedType); + protected abstract Object fromJson(Reader reader, Type resolvedType) throws IOException; protected abstract Object fromJson(String payload, Type resolvedType); - protected abstract void toJson(Object payload, Type resolvedType, Writer writer); + protected abstract void toJson(Object payload, Type resolvedType, Writer writer) throws IOException; protected abstract String toJson(Object payload, Type resolvedType); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/GsonMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/GsonMessageConverter.java index 95de58ede26..0e15dfc09b7 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/GsonMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/GsonMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2024 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,6 +16,7 @@ package org.springframework.messaging.converter; +import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.lang.reflect.ParameterizedType; @@ -88,13 +89,14 @@ public class GsonMessageConverter extends AbstractJsonMessageConverter { } @Override - protected void toJson(Object payload, Type resolvedType, Writer writer) { + protected void toJson(Object payload, Type resolvedType, Writer writer) throws IOException { if (resolvedType instanceof ParameterizedType) { getGson().toJson(payload, resolvedType, writer); } else { getGson().toJson(payload, writer); } + writer.flush(); } @Override diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java index 44e4aa830f3..75decdb8458 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -76,13 +76,9 @@ public class KotlinSerializationJsonMessageConverter extends AbstractJsonMessage } @Override - protected void toJson(Object payload, Type resolvedType, Writer writer) { - try { - writer.write(toJson(payload, resolvedType).toCharArray()); - } - catch (IOException ex) { - throw new MessageConversionException("Could not write JSON: " + ex.getMessage(), ex); - } + protected void toJson(Object payload, Type resolvedType, Writer writer) throws IOException { + writer.write(toJson(payload, resolvedType).toCharArray()); + writer.flush(); } @Override @@ -106,4 +102,5 @@ public class KotlinSerializationJsonMessageConverter extends AbstractJsonMessage } return serializer; } + } diff --git a/spring-orm/spring-orm.gradle b/spring-orm/spring-orm.gradle index db00899a11f..9f39583ece1 100644 --- a/spring-orm/spring-orm.gradle +++ b/spring-orm/spring-orm.gradle @@ -11,7 +11,7 @@ dependencies { optional(project(":spring-web")) optional("jakarta.servlet:jakarta.servlet-api") optional("org.eclipse.persistence:org.eclipse.persistence.jpa") - optional("org.hibernate:hibernate-core-jakarta") + optional("org.hibernate:hibernate-core") testImplementation(project(":spring-core-test")) testImplementation(testFixtures(project(":spring-beans"))) testImplementation(testFixtures(project(":spring-context"))) diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateObjectRetrievalFailureException.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateObjectRetrievalFailureException.java index 150ae55c6d1..e06342c26a6 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateObjectRetrievalFailureException.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateObjectRetrievalFailureException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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,13 +16,10 @@ package org.springframework.orm.hibernate5; -import org.hibernate.HibernateException; import org.hibernate.UnresolvableObjectException; import org.hibernate.WrongClassException; -import org.springframework.lang.Nullable; import org.springframework.orm.ObjectRetrievalFailureException; -import org.springframework.util.ReflectionUtils; /** * Hibernate-specific subclass of ObjectRetrievalFailureException. @@ -36,24 +33,11 @@ import org.springframework.util.ReflectionUtils; public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException { public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex) { - super(ex.getEntityName(), getIdentifier(ex), ex.getMessage(), ex); + super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex); } public HibernateObjectRetrievalFailureException(WrongClassException ex) { - super(ex.getEntityName(), getIdentifier(ex), ex.getMessage(), ex); - } - - - @Nullable - static Object getIdentifier(HibernateException hibEx) { - try { - // getIdentifier declares Serializable return value on 5.x but Object on 6.x - // -> not binary compatible, let's invoke it reflectively for the time being - return ReflectionUtils.invokeMethod(hibEx.getClass().getMethod("getIdentifier"), hibEx); - } - catch (NoSuchMethodException ex) { - return null; - } + super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex); } } diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateOperations.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateOperations.java deleted file mode 100644 index 0bd481af29f..00000000000 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateOperations.java +++ /dev/null @@ -1,857 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://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.orm.hibernate5; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import org.hibernate.Filter; -import org.hibernate.LockMode; -import org.hibernate.ReplicationMode; -import org.hibernate.criterion.DetachedCriteria; - -import org.springframework.dao.DataAccessException; -import org.springframework.lang.Nullable; - -/** - * Interface that specifies a common set of Hibernate operations as well as - * a general {@link #execute} method for Session-based lambda expressions. - * Implemented by {@link HibernateTemplate}. Not often used, but a useful option - * to enhance testability, as it can easily be mocked or stubbed. - * - *

Defines {@code HibernateTemplate}'s data access methods that mirror various - * {@link org.hibernate.Session} methods. Users are strongly encouraged to read the - * Hibernate {@code Session} javadocs for details on the semantics of those methods. - * - *

A deprecation note: While {@link HibernateTemplate} and this operations - * interface are being kept around for backwards compatibility in terms of the data - * access implementation style in Spring applications, we strongly recommend the use - * of native {@link org.hibernate.Session} access code for non-trivial interactions. - * This in particular affects parameterized queries where - on Java 8+ - a custom - * {@link HibernateCallback} lambda code block with {@code createQuery} and several - * {@code setParameter} calls on the {@link org.hibernate.query.Query} interface - * is an elegant solution, to be executed via the general {@link #execute} method. - * All such operations which benefit from a lambda variant have been marked as - * {@code deprecated} on this interface. - * - *

A Hibernate compatibility note: {@link HibernateTemplate} and the - * operations on this interface generally aim to be applicable across all Hibernate - * versions. In terms of binary compatibility, Spring ships a variant for each major - * generation of Hibernate (in the present case: Hibernate ORM 5.x). However, due to - * refactorings and removals in Hibernate ORM 5.3, some variants - in particular - * legacy positional parameters starting from index 0 - do not work anymore. - * All affected operations are marked as deprecated; please replace them with the - * general {@link #execute} method and custom lambda blocks creating the queries, - * ideally setting named parameters through {@link org.hibernate.query.Query}. - * Please be aware that deprecated operations are known to work with Hibernate - * ORM 5.2 but may not work with Hibernate ORM 5.3 and higher anymore. - * - * @author Juergen Hoeller - * @since 4.2 - * @see HibernateTemplate - * @see org.hibernate.Session - * @see HibernateTransactionManager - */ -public interface HibernateOperations { - - /** - * Execute the action specified by the given action object within a - * {@link org.hibernate.Session}. - *

Application exceptions thrown by the action object get propagated - * to the caller (can only be unchecked). Hibernate exceptions are - * transformed into appropriate DAO ones. Allows for returning a result - * object, that is a domain object or a collection of domain objects. - *

Note: Callback code is not supposed to handle transactions itself! - * Use an appropriate transaction manager like - * {@link HibernateTransactionManager}. Generally, callback code must not - * touch any {@code Session} lifecycle methods, like close, - * disconnect, or reconnect, to let the template do its work. - * @param action callback object that specifies the Hibernate action - * @return a result object returned by the action, or {@code null} - * @throws DataAccessException in case of Hibernate errors - * @see HibernateTransactionManager - * @see org.hibernate.Session - */ - @Nullable - T execute(HibernateCallback action) throws DataAccessException; - - - //------------------------------------------------------------------------- - // Convenience methods for loading individual objects - //------------------------------------------------------------------------- - - /** - * Return the persistent instance of the given entity class - * with the given identifier, or {@code null} if not found. - *

This method is a thin wrapper around - * {@link org.hibernate.Session#get(Class, Serializable)} for convenience. - * For an explanation of the exact semantics of this method, please do refer to - * the Hibernate API documentation in the first instance. - * @param entityClass a persistent class - * @param id the identifier of the persistent instance - * @return the persistent instance, or {@code null} if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#get(Class, Serializable) - */ - @Nullable - T get(Class entityClass, Serializable id) throws DataAccessException; - - /** - * Return the persistent instance of the given entity class - * with the given identifier, or {@code null} if not found. - *

Obtains the specified lock mode if the instance exists. - *

This method is a thin wrapper around - * {@link org.hibernate.Session#get(Class, Serializable, LockMode)} for convenience. - * For an explanation of the exact semantics of this method, please do refer to - * the Hibernate API documentation in the first instance. - * @param entityClass a persistent class - * @param id the identifier of the persistent instance - * @param lockMode the lock mode to obtain - * @return the persistent instance, or {@code null} if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#get(Class, Serializable, LockMode) - */ - @Nullable - T get(Class entityClass, Serializable id, LockMode lockMode) throws DataAccessException; - - /** - * Return the persistent instance of the given entity class - * with the given identifier, or {@code null} if not found. - *

This method is a thin wrapper around - * {@link org.hibernate.Session#get(String, Serializable)} for convenience. - * For an explanation of the exact semantics of this method, please do refer to - * the Hibernate API documentation in the first instance. - * @param entityName the name of the persistent entity - * @param id the identifier of the persistent instance - * @return the persistent instance, or {@code null} if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#get(Class, Serializable) - */ - @Nullable - Object get(String entityName, Serializable id) throws DataAccessException; - - /** - * Return the persistent instance of the given entity class - * with the given identifier, or {@code null} if not found. - * Obtains the specified lock mode if the instance exists. - *

This method is a thin wrapper around - * {@link org.hibernate.Session#get(String, Serializable, LockMode)} for convenience. - * For an explanation of the exact semantics of this method, please do refer to - * the Hibernate API documentation in the first instance. - * @param entityName the name of the persistent entity - * @param id the identifier of the persistent instance - * @param lockMode the lock mode to obtain - * @return the persistent instance, or {@code null} if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#get(Class, Serializable, LockMode) - */ - @Nullable - Object get(String entityName, Serializable id, LockMode lockMode) throws DataAccessException; - - /** - * Return the persistent instance of the given entity class - * with the given identifier, throwing an exception if not found. - *

This method is a thin wrapper around - * {@link org.hibernate.Session#load(Class, Serializable)} for convenience. - * For an explanation of the exact semantics of this method, please do refer to - * the Hibernate API documentation in the first instance. - * @param entityClass a persistent class - * @param id the identifier of the persistent instance - * @return the persistent instance - * @throws org.springframework.orm.ObjectRetrievalFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#load(Class, Serializable) - */ - T load(Class entityClass, Serializable id) throws DataAccessException; - - /** - * Return the persistent instance of the given entity class - * with the given identifier, throwing an exception if not found. - * Obtains the specified lock mode if the instance exists. - *

This method is a thin wrapper around - * {@link org.hibernate.Session#load(Class, Serializable, LockMode)} for convenience. - * For an explanation of the exact semantics of this method, please do refer to - * the Hibernate API documentation in the first instance. - * @param entityClass a persistent class - * @param id the identifier of the persistent instance - * @param lockMode the lock mode to obtain - * @return the persistent instance - * @throws org.springframework.orm.ObjectRetrievalFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#load(Class, Serializable) - */ - T load(Class entityClass, Serializable id, LockMode lockMode) throws DataAccessException; - - /** - * Return the persistent instance of the given entity class - * with the given identifier, throwing an exception if not found. - *

This method is a thin wrapper around - * {@link org.hibernate.Session#load(String, Serializable)} for convenience. - * For an explanation of the exact semantics of this method, please do refer to - * the Hibernate API documentation in the first instance. - * @param entityName the name of the persistent entity - * @param id the identifier of the persistent instance - * @return the persistent instance - * @throws org.springframework.orm.ObjectRetrievalFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#load(Class, Serializable) - */ - Object load(String entityName, Serializable id) throws DataAccessException; - - /** - * Return the persistent instance of the given entity class - * with the given identifier, throwing an exception if not found. - *

Obtains the specified lock mode if the instance exists. - *

This method is a thin wrapper around - * {@link org.hibernate.Session#load(String, Serializable, LockMode)} for convenience. - * For an explanation of the exact semantics of this method, please do refer to - * the Hibernate API documentation in the first instance. - * @param entityName the name of the persistent entity - * @param id the identifier of the persistent instance - * @param lockMode the lock mode to obtain - * @return the persistent instance - * @throws org.springframework.orm.ObjectRetrievalFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#load(Class, Serializable) - */ - Object load(String entityName, Serializable id, LockMode lockMode) throws DataAccessException; - - /** - * Return all persistent instances of the given entity class. - * Note: Use queries or criteria for retrieving a specific subset. - * @param entityClass a persistent class - * @return a {@link List} containing 0 or more persistent instances - * @throws DataAccessException if there is a Hibernate error - * @see org.hibernate.Session#createCriteria - */ - List loadAll(Class entityClass) throws DataAccessException; - - /** - * Load the persistent instance with the given identifier - * into the given object, throwing an exception if not found. - *

This method is a thin wrapper around - * {@link org.hibernate.Session#load(Object, Serializable)} for convenience. - * For an explanation of the exact semantics of this method, please do refer to - * the Hibernate API documentation in the first instance. - * @param entity the object (of the target class) to load into - * @param id the identifier of the persistent instance - * @throws org.springframework.orm.ObjectRetrievalFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#load(Object, Serializable) - */ - void load(Object entity, Serializable id) throws DataAccessException; - - /** - * Re-read the state of the given persistent instance. - * @param entity the persistent instance to re-read - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#refresh(Object) - */ - void refresh(Object entity) throws DataAccessException; - - /** - * Re-read the state of the given persistent instance. - * Obtains the specified lock mode for the instance. - * @param entity the persistent instance to re-read - * @param lockMode the lock mode to obtain - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#refresh(Object, LockMode) - */ - void refresh(Object entity, LockMode lockMode) throws DataAccessException; - - /** - * Check whether the given object is in the Session cache. - * @param entity the persistence instance to check - * @return whether the given object is in the Session cache - * @throws DataAccessException if there is a Hibernate error - * @see org.hibernate.Session#contains - */ - boolean contains(Object entity) throws DataAccessException; - - /** - * Remove the given object from the {@link org.hibernate.Session} cache. - * @param entity the persistent instance to evict - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#evict - */ - void evict(Object entity) throws DataAccessException; - - /** - * Force initialization of a Hibernate proxy or persistent collection. - * @param proxy a proxy for a persistent object or a persistent collection - * @throws DataAccessException if we can't initialize the proxy, for example - * because it is not associated with an active Session - * @see org.hibernate.Hibernate#initialize - */ - void initialize(Object proxy) throws DataAccessException; - - /** - * Return an enabled Hibernate {@link Filter} for the given filter name. - * The returned {@code Filter} instance can be used to set filter parameters. - * @param filterName the name of the filter - * @return the enabled Hibernate {@code Filter} (either already - * enabled or enabled on the fly by this operation) - * @throws IllegalStateException if we are not running within a - * transactional Session (in which case this operation does not make sense) - */ - Filter enableFilter(String filterName) throws IllegalStateException; - - - //------------------------------------------------------------------------- - // Convenience methods for storing individual objects - //------------------------------------------------------------------------- - - /** - * Obtain the specified lock level upon the given object, implicitly - * checking whether the corresponding database entry still exists. - * @param entity the persistent instance to lock - * @param lockMode the lock mode to obtain - * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#lock(Object, LockMode) - */ - void lock(Object entity, LockMode lockMode) throws DataAccessException; - - /** - * Obtain the specified lock level upon the given object, implicitly - * checking whether the corresponding database entry still exists. - * @param entityName the name of the persistent entity - * @param entity the persistent instance to lock - * @param lockMode the lock mode to obtain - * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#lock(String, Object, LockMode) - */ - void lock(String entityName, Object entity, LockMode lockMode) throws DataAccessException; - - /** - * Persist the given transient instance. - * @param entity the transient instance to persist - * @return the generated identifier - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#save(Object) - */ - Serializable save(Object entity) throws DataAccessException; - - /** - * Persist the given transient instance. - * @param entityName the name of the persistent entity - * @param entity the transient instance to persist - * @return the generated identifier - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#save(String, Object) - */ - Serializable save(String entityName, Object entity) throws DataAccessException; - - /** - * Update the given persistent instance, - * associating it with the current Hibernate {@link org.hibernate.Session}. - * @param entity the persistent instance to update - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#update(Object) - */ - void update(Object entity) throws DataAccessException; - - /** - * Update the given persistent instance, - * associating it with the current Hibernate {@link org.hibernate.Session}. - *

Obtains the specified lock mode if the instance exists, implicitly - * checking whether the corresponding database entry still exists. - * @param entity the persistent instance to update - * @param lockMode the lock mode to obtain - * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#update(Object) - */ - void update(Object entity, LockMode lockMode) throws DataAccessException; - - /** - * Update the given persistent instance, - * associating it with the current Hibernate {@link org.hibernate.Session}. - * @param entityName the name of the persistent entity - * @param entity the persistent instance to update - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#update(String, Object) - */ - void update(String entityName, Object entity) throws DataAccessException; - - /** - * Update the given persistent instance, - * associating it with the current Hibernate {@link org.hibernate.Session}. - *

Obtains the specified lock mode if the instance exists, implicitly - * checking whether the corresponding database entry still exists. - * @param entityName the name of the persistent entity - * @param entity the persistent instance to update - * @param lockMode the lock mode to obtain - * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#update(String, Object) - */ - void update(String entityName, Object entity, LockMode lockMode) throws DataAccessException; - - /** - * Save or update the given persistent instance, - * according to its id (matching the configured "unsaved-value"?). - * Associates the instance with the current Hibernate {@link org.hibernate.Session}. - * @param entity the persistent instance to save or update - * (to be associated with the Hibernate {@code Session}) - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#saveOrUpdate(Object) - */ - void saveOrUpdate(Object entity) throws DataAccessException; - - /** - * Save or update the given persistent instance, - * according to its id (matching the configured "unsaved-value"?). - * Associates the instance with the current Hibernate {@code Session}. - * @param entityName the name of the persistent entity - * @param entity the persistent instance to save or update - * (to be associated with the Hibernate {@code Session}) - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#saveOrUpdate(String, Object) - */ - void saveOrUpdate(String entityName, Object entity) throws DataAccessException; - - /** - * Persist the state of the given detached instance according to the - * given replication mode, reusing the current identifier value. - * @param entity the persistent object to replicate - * @param replicationMode the Hibernate ReplicationMode - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#replicate(Object, ReplicationMode) - */ - void replicate(Object entity, ReplicationMode replicationMode) throws DataAccessException; - - /** - * Persist the state of the given detached instance according to the - * given replication mode, reusing the current identifier value. - * @param entityName the name of the persistent entity - * @param entity the persistent object to replicate - * @param replicationMode the Hibernate ReplicationMode - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#replicate(String, Object, ReplicationMode) - */ - void replicate(String entityName, Object entity, ReplicationMode replicationMode) throws DataAccessException; - - /** - * Persist the given transient instance. Follows JSR-220 semantics. - *

Similar to {@code save}, associating the given object - * with the current Hibernate {@link org.hibernate.Session}. - * @param entity the persistent instance to persist - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#persist(Object) - * @see #save - */ - void persist(Object entity) throws DataAccessException; - - /** - * Persist the given transient instance. Follows JSR-220 semantics. - *

Similar to {@code save}, associating the given object - * with the current Hibernate {@link org.hibernate.Session}. - * @param entityName the name of the persistent entity - * @param entity the persistent instance to persist - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#persist(String, Object) - * @see #save - */ - void persist(String entityName, Object entity) throws DataAccessException; - - /** - * Copy the state of the given object onto the persistent object - * with the same identifier. Follows JSR-220 semantics. - *

Similar to {@code saveOrUpdate}, but never associates the given - * object with the current Hibernate Session. In case of a new entity, - * the state will be copied over as well. - *

Note that {@code merge} will not update the identifiers - * in the passed-in object graph (in contrast to TopLink)! Consider - * registering Spring's {@code IdTransferringMergeEventListener} if - * you would like to have newly assigned ids transferred to the original - * object graph too. - * @param entity the object to merge with the corresponding persistence instance - * @return the updated, registered persistent instance - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#merge(Object) - * @see #saveOrUpdate - */ - T merge(T entity) throws DataAccessException; - - /** - * Copy the state of the given object onto the persistent object - * with the same identifier. Follows JSR-220 semantics. - *

Similar to {@code saveOrUpdate}, but never associates the given - * object with the current Hibernate {@link org.hibernate.Session}. In - * the case of a new entity, the state will be copied over as well. - *

Note that {@code merge} will not update the identifiers - * in the passed-in object graph (in contrast to TopLink)! Consider - * registering Spring's {@code IdTransferringMergeEventListener} - * if you would like to have newly assigned ids transferred to the - * original object graph too. - * @param entityName the name of the persistent entity - * @param entity the object to merge with the corresponding persistence instance - * @return the updated, registered persistent instance - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#merge(String, Object) - * @see #saveOrUpdate - */ - T merge(String entityName, T entity) throws DataAccessException; - - /** - * Delete the given persistent instance. - * @param entity the persistent instance to delete - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#delete(Object) - */ - void delete(Object entity) throws DataAccessException; - - /** - * Delete the given persistent instance. - *

Obtains the specified lock mode if the instance exists, implicitly - * checking whether the corresponding database entry still exists. - * @param entity the persistent instance to delete - * @param lockMode the lock mode to obtain - * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#delete(Object) - */ - void delete(Object entity, LockMode lockMode) throws DataAccessException; - - /** - * Delete the given persistent instance. - * @param entityName the name of the persistent entity - * @param entity the persistent instance to delete - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#delete(Object) - */ - void delete(String entityName, Object entity) throws DataAccessException; - - /** - * Delete the given persistent instance. - *

Obtains the specified lock mode if the instance exists, implicitly - * checking whether the corresponding database entry still exists. - * @param entityName the name of the persistent entity - * @param entity the persistent instance to delete - * @param lockMode the lock mode to obtain - * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#delete(Object) - */ - void delete(String entityName, Object entity, LockMode lockMode) throws DataAccessException; - - /** - * Delete all given persistent instances. - *

This can be combined with any of the find methods to delete by query - * in two lines of code. - * @param entities the persistent instances to delete - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#delete(Object) - */ - void deleteAll(Collection entities) throws DataAccessException; - - /** - * Flush all pending saves, updates and deletes to the database. - *

Only invoke this for selective eager flushing, for example when - * JDBC code needs to see certain changes within the same transaction. - * Else, it is preferable to rely on auto-flushing at transaction - * completion. - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#flush - */ - void flush() throws DataAccessException; - - /** - * Remove all objects from the {@link org.hibernate.Session} cache, and - * cancel all pending saves, updates and deletes. - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#clear - */ - void clear() throws DataAccessException; - - - //------------------------------------------------------------------------- - // Convenience finder methods for detached criteria - //------------------------------------------------------------------------- - - /** - * Execute a query based on a given Hibernate criteria object. - * @param criteria the detached Hibernate criteria object. - * Note: Do not reuse criteria objects! They need to recreated per execution, - * due to the suboptimal design of Hibernate's criteria facility. - * @return a {@link List} containing 0 or more persistent instances - * @throws DataAccessException in case of Hibernate errors - * @see DetachedCriteria#getExecutableCriteria(org.hibernate.Session) - */ - List findByCriteria(DetachedCriteria criteria) throws DataAccessException; - - /** - * Execute a query based on the given Hibernate criteria object. - * @param criteria the detached Hibernate criteria object. - * Note: Do not reuse criteria objects! They need to recreated per execution, - * due to the suboptimal design of Hibernate's criteria facility. - * @param firstResult the index of the first result object to be retrieved - * (numbered from 0) - * @param maxResults the maximum number of result objects to retrieve - * (or <=0 for no limit) - * @return a {@link List} containing 0 or more persistent instances - * @throws DataAccessException in case of Hibernate errors - * @see DetachedCriteria#getExecutableCriteria(org.hibernate.Session) - * @see org.hibernate.Criteria#setFirstResult(int) - * @see org.hibernate.Criteria#setMaxResults(int) - */ - List findByCriteria(DetachedCriteria criteria, int firstResult, int maxResults) throws DataAccessException; - - /** - * Execute a query based on the given example entity object. - * @param exampleEntity an instance of the desired entity, - * serving as example for "query-by-example" - * @return a {@link List} containing 0 or more persistent instances - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.criterion.Example#create(Object) - */ - List findByExample(T exampleEntity) throws DataAccessException; - - /** - * Execute a query based on the given example entity object. - * @param entityName the name of the persistent entity - * @param exampleEntity an instance of the desired entity, - * serving as example for "query-by-example" - * @return a {@link List} containing 0 or more persistent instances - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.criterion.Example#create(Object) - */ - List findByExample(String entityName, T exampleEntity) throws DataAccessException; - - /** - * Execute a query based on a given example entity object. - * @param exampleEntity an instance of the desired entity, - * serving as example for "query-by-example" - * @param firstResult the index of the first result object to be retrieved - * (numbered from 0) - * @param maxResults the maximum number of result objects to retrieve - * (or <=0 for no limit) - * @return a {@link List} containing 0 or more persistent instances - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.criterion.Example#create(Object) - * @see org.hibernate.Criteria#setFirstResult(int) - * @see org.hibernate.Criteria#setMaxResults(int) - */ - List findByExample(T exampleEntity, int firstResult, int maxResults) throws DataAccessException; - - /** - * Execute a query based on a given example entity object. - * @param entityName the name of the persistent entity - * @param exampleEntity an instance of the desired entity, - * serving as example for "query-by-example" - * @param firstResult the index of the first result object to be retrieved - * (numbered from 0) - * @param maxResults the maximum number of result objects to retrieve - * (or <=0 for no limit) - * @return a {@link List} containing 0 or more persistent instances - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.criterion.Example#create(Object) - * @see org.hibernate.Criteria#setFirstResult(int) - * @see org.hibernate.Criteria#setMaxResults(int) - */ - List findByExample(String entityName, T exampleEntity, int firstResult, int maxResults) - throws DataAccessException; - - - //------------------------------------------------------------------------- - // Convenience finder methods for HQL strings - //------------------------------------------------------------------------- - - /** - * Execute an HQL query, binding a number of values to "?" parameters - * in the query string. - * @param queryString a query expressed in Hibernate's query language - * @param values the values of the parameters - * @return a {@link List} containing the results of the query execution - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#createQuery - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - List find(String queryString, Object... values) throws DataAccessException; - - /** - * Execute an HQL query, binding one value to a ":" named parameter - * in the query string. - * @param queryString a query expressed in Hibernate's query language - * @param paramName the name of the parameter - * @param value the value of the parameter - * @return a {@link List} containing the results of the query execution - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#getNamedQuery(String) - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - List findByNamedParam(String queryString, String paramName, Object value) throws DataAccessException; - - /** - * Execute an HQL query, binding a number of values to ":" named - * parameters in the query string. - * @param queryString a query expressed in Hibernate's query language - * @param paramNames the names of the parameters - * @param values the values of the parameters - * @return a {@link List} containing the results of the query execution - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#getNamedQuery(String) - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - List findByNamedParam(String queryString, String[] paramNames, Object[] values) throws DataAccessException; - - /** - * Execute an HQL query, binding the properties of the given bean to - * named parameters in the query string. - * @param queryString a query expressed in Hibernate's query language - * @param valueBean the values of the parameters - * @return a {@link List} containing the results of the query execution - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Query#setProperties - * @see org.hibernate.Session#createQuery - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - List findByValueBean(String queryString, Object valueBean) throws DataAccessException; - - - //------------------------------------------------------------------------- - // Convenience finder methods for named queries - //------------------------------------------------------------------------- - - /** - * Execute a named query binding a number of values to "?" parameters - * in the query string. - *

A named query is defined in a Hibernate mapping file. - * @param queryName the name of a Hibernate query in a mapping file - * @param values the values of the parameters - * @return a {@link List} containing the results of the query execution - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#getNamedQuery(String) - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - List findByNamedQuery(String queryName, Object... values) throws DataAccessException; - - /** - * Execute a named query, binding one value to a ":" named parameter - * in the query string. - *

A named query is defined in a Hibernate mapping file. - * @param queryName the name of a Hibernate query in a mapping file - * @param paramName the name of parameter - * @param value the value of the parameter - * @return a {@link List} containing the results of the query execution - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#getNamedQuery(String) - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - List findByNamedQueryAndNamedParam(String queryName, String paramName, Object value) - throws DataAccessException; - - /** - * Execute a named query, binding a number of values to ":" named - * parameters in the query string. - *

A named query is defined in a Hibernate mapping file. - * @param queryName the name of a Hibernate query in a mapping file - * @param paramNames the names of the parameters - * @param values the values of the parameters - * @return a {@link List} containing the results of the query execution - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#getNamedQuery(String) - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - List findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values) - throws DataAccessException; - - /** - * Execute a named query, binding the properties of the given bean to - * ":" named parameters in the query string. - *

A named query is defined in a Hibernate mapping file. - * @param queryName the name of a Hibernate query in a mapping file - * @param valueBean the values of the parameters - * @return a {@link List} containing the results of the query execution - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Query#setProperties - * @see org.hibernate.Session#getNamedQuery(String) - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - List findByNamedQueryAndValueBean(String queryName, Object valueBean) throws DataAccessException; - - - //------------------------------------------------------------------------- - // Convenience query methods for iteration and bulk updates/deletes - //------------------------------------------------------------------------- - - /** - * Execute a query for persistent instances, binding a number of - * values to "?" parameters in the query string. - *

Returns the results as an {@link Iterator}. Entities returned are - * initialized on demand. See the Hibernate API documentation for details. - * @param queryString a query expressed in Hibernate's query language - * @param values the values of the parameters - * @return an {@link Iterator} containing 0 or more persistent instances - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#createQuery - * @see org.hibernate.Query#iterate - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - Iterator iterate(String queryString, Object... values) throws DataAccessException; - - /** - * Immediately close an {@link Iterator} created by any of the various - * {@code iterate(..)} operations, instead of waiting until the - * session is closed or disconnected. - * @param it the {@code Iterator} to close - * @throws DataAccessException if the {@code Iterator} could not be closed - * @see org.hibernate.Hibernate#close - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - void closeIterator(Iterator it) throws DataAccessException; - - /** - * Update/delete all objects according to the given query, binding a number of - * values to "?" parameters in the query string. - * @param queryString an update/delete query expressed in Hibernate's query language - * @param values the values of the parameters - * @return the number of instances updated/deleted - * @throws DataAccessException in case of Hibernate errors - * @see org.hibernate.Session#createQuery - * @see org.hibernate.Query#executeUpdate - * @deprecated as of 5.0.4, in favor of a custom {@link HibernateCallback} - * lambda code block passed to the general {@link #execute} method - */ - @Deprecated - int bulkUpdate(String queryString, Object... values) throws DataAccessException; - -} diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateOptimisticLockingFailureException.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateOptimisticLockingFailureException.java index 0246df5a281..c3bbfe98a33 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateOptimisticLockingFailureException.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateOptimisticLockingFailureException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -35,7 +35,7 @@ import org.springframework.orm.ObjectOptimisticLockingFailureException; public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException { public HibernateOptimisticLockingFailureException(StaleObjectStateException ex) { - super(ex.getEntityName(), HibernateObjectRetrievalFailureException.getIdentifier(ex), ex.getMessage(), ex); + super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex); } public HibernateOptimisticLockingFailureException(StaleStateException ex) { diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTemplate.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTemplate.java deleted file mode 100644 index 51ef7fd4620..00000000000 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTemplate.java +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * Copyright 2002-2023 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 - * - * https://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.orm.hibernate5; - -import java.io.Serializable; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import jakarta.persistence.PersistenceException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.Criteria; -import org.hibernate.Filter; -import org.hibernate.FlushMode; -import org.hibernate.Hibernate; -import org.hibernate.HibernateException; -import org.hibernate.LockMode; -import org.hibernate.LockOptions; -import org.hibernate.ReplicationMode; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.criterion.DetachedCriteria; -import org.hibernate.criterion.Example; -import org.hibernate.query.Query; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.lang.Nullable; -import org.springframework.transaction.support.ResourceHolderSupport; -import org.springframework.transaction.support.TransactionSynchronizationManager; -import org.springframework.util.Assert; - -/** - * Helper class that simplifies Hibernate data access code. Automatically - * converts HibernateExceptions into DataAccessExceptions, following the - * {@code org.springframework.dao} exception hierarchy. - * - *

The central method is {@code execute}, supporting Hibernate access code - * implementing the {@link HibernateCallback} interface. It provides Hibernate Session - * handling such that neither the HibernateCallback implementation nor the calling - * code needs to explicitly care about retrieving/closing Hibernate Sessions, - * or handling Session lifecycle exceptions. For typical single step actions, - * there are various convenience methods (find, load, saveOrUpdate, delete). - * - *

Can be used within a service implementation via direct instantiation - * with a SessionFactory reference, or get prepared in an application context - * and given to services as bean reference. Note: The SessionFactory should - * always be configured as bean in the application context, in the first case - * given to the service directly, in the second case to the prepared template. - * - *

NOTE: Hibernate access code can also be coded against the native Hibernate - * {@link Session}. Hence, for newly started projects, consider adopting the standard - * Hibernate style of coding against {@link SessionFactory#getCurrentSession()}. - * Alternatively, use {@link #execute(HibernateCallback)} with Java 8 lambda code blocks - * against the callback-provided {@code Session} which results in elegant code as well, - * decoupled from the Hibernate Session lifecycle. The remaining operations on this - * HibernateTemplate are deprecated in the meantime and primarily exist as a migration - * helper for older Hibernate 3.x/4.x data access code in existing applications. - * - * @author Juergen Hoeller - * @since 4.2 - * @see #setSessionFactory - * @see HibernateCallback - * @see Session - * @see LocalSessionFactoryBean - * @see HibernateTransactionManager - * @see org.springframework.orm.hibernate5.support.OpenSessionInViewFilter - * @see org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor - */ -public class HibernateTemplate implements HibernateOperations, InitializingBean { - - protected final Log logger = LogFactory.getLog(getClass()); - - @Nullable - private SessionFactory sessionFactory; - - @Nullable - private String[] filterNames; - - private boolean exposeNativeSession = false; - - private boolean checkWriteOperations = true; - - private boolean cacheQueries = false; - - @Nullable - private String queryCacheRegion; - - private int fetchSize = 0; - - private int maxResults = 0; - - - /** - * Create a new HibernateTemplate instance. - */ - public HibernateTemplate() { - } - - /** - * Create a new HibernateTemplate instance. - * @param sessionFactory the SessionFactory to create Sessions with - */ - public HibernateTemplate(SessionFactory sessionFactory) { - setSessionFactory(sessionFactory); - afterPropertiesSet(); - } - - - /** - * Set the Hibernate SessionFactory that should be used to create - * Hibernate Sessions. - */ - public void setSessionFactory(@Nullable SessionFactory sessionFactory) { - this.sessionFactory = sessionFactory; - } - - /** - * Return the Hibernate SessionFactory that should be used to create - * Hibernate Sessions. - */ - @Nullable - public SessionFactory getSessionFactory() { - return this.sessionFactory; - } - - /** - * Obtain the SessionFactory for actual use. - * @return the SessionFactory (never {@code null}) - * @throws IllegalStateException in case of no SessionFactory set - * @since 5.0 - */ - protected final SessionFactory obtainSessionFactory() { - SessionFactory sessionFactory = getSessionFactory(); - Assert.state(sessionFactory != null, "No SessionFactory set"); - return sessionFactory; - } - - /** - * Set one or more names of Hibernate filters to be activated for all - * Sessions that this accessor works with. - *

Each of those filters will be enabled at the beginning of each - * operation and correspondingly disabled at the end of the operation. - * This will work for newly opened Sessions as well as for existing - * Sessions (for example, within a transaction). - * @see #enableFilters(Session) - * @see Session#enableFilter(String) - */ - public void setFilterNames(@Nullable String... filterNames) { - this.filterNames = filterNames; - } - - /** - * Return the names of Hibernate filters to be activated, if any. - */ - @Nullable - public String[] getFilterNames() { - return this.filterNames; - } - - /** - * Set whether to expose the native Hibernate Session to - * HibernateCallback code. - *

Default is "false": a Session proxy will be returned, suppressing - * {@code close} calls and automatically applying query cache - * settings and transaction timeouts. - * @see HibernateCallback - * @see Session - * @see #setCacheQueries - * @see #setQueryCacheRegion - * @see #prepareQuery - * @see #prepareCriteria - */ - public void setExposeNativeSession(boolean exposeNativeSession) { - this.exposeNativeSession = exposeNativeSession; - } - - /** - * Return whether to expose the native Hibernate Session to - * HibernateCallback code, or rather a Session proxy. - */ - public boolean isExposeNativeSession() { - return this.exposeNativeSession; - } - - /** - * Set whether to check that the Hibernate Session is not in read-only mode - * in case of write operations (save/update/delete). - *

Default is "true", for fail-fast behavior when attempting write operations - * within a read-only transaction. Turn this off to allow save/update/delete - * on a Session with flush mode MANUAL. - * @see #checkWriteOperationAllowed - * @see org.springframework.transaction.TransactionDefinition#isReadOnly - */ - public void setCheckWriteOperations(boolean checkWriteOperations) { - this.checkWriteOperations = checkWriteOperations; - } - - /** - * Return whether to check that the Hibernate Session is not in read-only - * mode in case of write operations (save/update/delete). - */ - public boolean isCheckWriteOperations() { - return this.checkWriteOperations; - } - - /** - * Set whether to cache all queries executed by this template. - *

If this is "true", all Query and Criteria objects created by - * this template will be marked as cacheable (including all - * queries through find methods). - *

To specify the query region to be used for queries cached - * by this template, set the "queryCacheRegion" property. - * @see #setQueryCacheRegion - * @see Query#setCacheable - * @see Criteria#setCacheable - */ - public void setCacheQueries(boolean cacheQueries) { - this.cacheQueries = cacheQueries; - } - - /** - * Return whether to cache all queries executed by this template. - */ - public boolean isCacheQueries() { - return this.cacheQueries; - } - - /** - * Set the name of the cache region for queries executed by this template. - *

If this is specified, it will be applied to all Query and Criteria objects - * created by this template (including all queries through find methods). - *

The cache region will not take effect unless queries created by this - * template are configured to be cached via the "cacheQueries" property. - * @see #setCacheQueries - * @see Query#setCacheRegion - * @see Criteria#setCacheRegion - */ - public void setQueryCacheRegion(@Nullable String queryCacheRegion) { - this.queryCacheRegion = queryCacheRegion; - } - - /** - * Return the name of the cache region for queries executed by this template. - */ - @Nullable - public String getQueryCacheRegion() { - return this.queryCacheRegion; - } - - /** - * Set the fetch size for this HibernateTemplate. This is important for processing - * large result sets: Setting this higher than the default value will increase - * processing speed at the cost of memory consumption; setting this lower can - * avoid transferring row data that will never be read by the application. - *

Default is 0, indicating to use the JDBC driver's default. - */ - public void setFetchSize(int fetchSize) { - this.fetchSize = fetchSize; - } - - /** - * Return the fetch size specified for this HibernateTemplate. - */ - public int getFetchSize() { - return this.fetchSize; - } - - /** - * Set the maximum number of rows for this HibernateTemplate. This is important - * for processing subsets of large result sets, avoiding to read and hold - * the entire result set in the database or in the JDBC driver if we're - * never interested in the entire result in the first place (for example, - * when performing searches that might return a large number of matches). - *

Default is 0, indicating to use the JDBC driver's default. - */ - public void setMaxResults(int maxResults) { - this.maxResults = maxResults; - } - - /** - * Return the maximum number of rows specified for this HibernateTemplate. - */ - public int getMaxResults() { - return this.maxResults; - } - - @Override - public void afterPropertiesSet() { - if (getSessionFactory() == null) { - throw new IllegalArgumentException("Property 'sessionFactory' is required"); - } - } - - - @Override - @Nullable - public T execute(HibernateCallback action) throws DataAccessException { - return doExecute(action, false); - } - - /** - * Execute the action specified by the given action object within a - * native {@link Session}. - *

This execute variant overrides the template-wide - * {@link #isExposeNativeSession() "exposeNativeSession"} setting. - * @param action callback object that specifies the Hibernate action - * @return a result object returned by the action, or {@code null} - * @throws DataAccessException in case of Hibernate errors - */ - @Nullable - public T executeWithNativeSession(HibernateCallback action) { - return doExecute(action, true); - } - - /** - * Execute the action specified by the given action object within a Session. - * @param action callback object that specifies the Hibernate action - * @param enforceNativeSession whether to enforce exposure of the native - * Hibernate Session to callback code - * @return a result object returned by the action, or {@code null} - * @throws DataAccessException in case of Hibernate errors - */ - @Nullable - protected T doExecute(HibernateCallback action, boolean enforceNativeSession) throws DataAccessException { - Assert.notNull(action, "Callback object must not be null"); - - Session session = null; - boolean isNew = false; - try { - session = obtainSessionFactory().getCurrentSession(); - } - catch (HibernateException ex) { - logger.debug("Could not retrieve pre-bound Hibernate session", ex); - } - if (session == null) { - session = obtainSessionFactory().openSession(); - session.setHibernateFlushMode(FlushMode.MANUAL); - isNew = true; - } - - try { - enableFilters(session); - Session sessionToExpose = - (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session)); - return action.doInHibernate(sessionToExpose); - } - catch (HibernateException ex) { - throw SessionFactoryUtils.convertHibernateAccessException(ex); - } - catch (PersistenceException ex) { - if (ex.getCause() instanceof HibernateException hibernateEx) { - throw SessionFactoryUtils.convertHibernateAccessException(hibernateEx); - } - throw ex; - } - catch (RuntimeException ex) { - // Callback code threw application exception... - throw ex; - } - finally { - if (isNew) { - SessionFactoryUtils.closeSession(session); - } - else { - disableFilters(session); - } - } - } - - /** - * Create a close-suppressing proxy for the given Hibernate Session. - * The proxy also prepares returned Query and Criteria objects. - * @param session the Hibernate Session to create a proxy for - * @return the Session proxy - * @see Session#close() - * @see #prepareQuery - * @see #prepareCriteria - */ - protected Session createSessionProxy(Session session) { - return (Session) Proxy.newProxyInstance( - session.getClass().getClassLoader(), new Class[] {Session.class}, - new CloseSuppressingInvocationHandler(session)); - } - - /** - * Enable the specified filters on the given Session. - * @param session the current Hibernate Session - * @see #setFilterNames - * @see Session#enableFilter(String) - */ - protected void enableFilters(Session session) { - String[] filterNames = getFilterNames(); - if (filterNames != null) { - for (String filterName : filterNames) { - session.enableFilter(filterName); - } - } - } - - /** - * Disable the specified filters on the given Session. - * @param session the current Hibernate Session - * @see #setFilterNames - * @see Session#disableFilter(String) - */ - protected void disableFilters(Session session) { - String[] filterNames = getFilterNames(); - if (filterNames != null) { - for (String filterName : filterNames) { - session.disableFilter(filterName); - } - } - } - - - //------------------------------------------------------------------------- - // Convenience methods for loading individual objects - //------------------------------------------------------------------------- - - @Override - @Nullable - public T get(Class entityClass, Serializable id) throws DataAccessException { - return get(entityClass, id, null); - } - - @Override - @Nullable - public T get(Class entityClass, Serializable id, @Nullable LockMode lockMode) throws DataAccessException { - return executeWithNativeSession(session -> { - if (lockMode != null) { - return session.get(entityClass, id, new LockOptions(lockMode)); - } - else { - return session.get(entityClass, id); - } - }); - } - - @Override - @Nullable - public Object get(String entityName, Serializable id) throws DataAccessException { - return get(entityName, id, null); - } - - @Override - @Nullable - public Object get(String entityName, Serializable id, @Nullable LockMode lockMode) throws DataAccessException { - return executeWithNativeSession(session -> { - if (lockMode != null) { - return session.get(entityName, id, new LockOptions(lockMode)); - } - else { - return session.get(entityName, id); - } - }); - } - - @Override - public T load(Class entityClass, Serializable id) throws DataAccessException { - return load(entityClass, id, null); - } - - @Override - public T load(Class entityClass, Serializable id, @Nullable LockMode lockMode) - throws DataAccessException { - - return nonNull(executeWithNativeSession(session -> { - if (lockMode != null) { - return session.load(entityClass, id, new LockOptions(lockMode)); - } - else { - return session.load(entityClass, id); - } - })); - } - - @Override - public Object load(String entityName, Serializable id) throws DataAccessException { - return load(entityName, id, null); - } - - @Override - public Object load(String entityName, Serializable id, @Nullable LockMode lockMode) throws DataAccessException { - return nonNull(executeWithNativeSession(session -> { - if (lockMode != null) { - return session.load(entityName, id, new LockOptions(lockMode)); - } - else { - return session.load(entityName, id); - } - })); - } - - @Override - @SuppressWarnings({"unchecked", "deprecation"}) - public List loadAll(Class entityClass) throws DataAccessException { - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Criteria criteria = session.createCriteria(entityClass); - criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); - prepareCriteria(criteria); - return criteria.list(); - })); - } - - @Override - public void load(Object entity, Serializable id) throws DataAccessException { - executeWithNativeSession(session -> { - session.load(entity, id); - return null; - }); - } - - @Override - public void refresh(Object entity) throws DataAccessException { - refresh(entity, null); - } - - @Override - public void refresh(Object entity, @Nullable LockMode lockMode) throws DataAccessException { - executeWithNativeSession(session -> { - if (lockMode != null) { - session.refresh(entity, new LockOptions(lockMode)); - } - else { - session.refresh(entity); - } - return null; - }); - } - - @Override - public boolean contains(Object entity) throws DataAccessException { - Boolean result = executeWithNativeSession(session -> session.contains(entity)); - Assert.state(result != null, "No contains result"); - return result; - } - - @Override - public void evict(Object entity) throws DataAccessException { - executeWithNativeSession(session -> { - session.evict(entity); - return null; - }); - } - - @Override - public void initialize(Object proxy) throws DataAccessException { - try { - Hibernate.initialize(proxy); - } - catch (HibernateException ex) { - throw SessionFactoryUtils.convertHibernateAccessException(ex); - } - } - - @Override - public Filter enableFilter(String filterName) throws IllegalStateException { - Session session = obtainSessionFactory().getCurrentSession(); - Filter filter = session.getEnabledFilter(filterName); - if (filter == null) { - filter = session.enableFilter(filterName); - } - return filter; - } - - - //------------------------------------------------------------------------- - // Convenience methods for storing individual objects - //------------------------------------------------------------------------- - - @Override - public void lock(Object entity, LockMode lockMode) throws DataAccessException { - executeWithNativeSession(session -> { - session.buildLockRequest(new LockOptions(lockMode)).lock(entity); - return null; - }); - } - - @Override - public void lock(String entityName, Object entity, LockMode lockMode) - throws DataAccessException { - - executeWithNativeSession(session -> { - session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity); - return null; - }); - } - - @Override - public Serializable save(Object entity) throws DataAccessException { - return nonNull(executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - return session.save(entity); - })); - } - - @Override - public Serializable save(String entityName, Object entity) throws DataAccessException { - return nonNull(executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - return session.save(entityName, entity); - })); - } - - @Override - public void update(Object entity) throws DataAccessException { - update(entity, null); - } - - @Override - public void update(Object entity, @Nullable LockMode lockMode) throws DataAccessException { - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - session.update(entity); - if (lockMode != null) { - session.buildLockRequest(new LockOptions(lockMode)).lock(entity); - } - return null; - }); - } - - @Override - public void update(String entityName, Object entity) throws DataAccessException { - update(entityName, entity, null); - } - - @Override - public void update(String entityName, Object entity, @Nullable LockMode lockMode) - throws DataAccessException { - - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - session.update(entityName, entity); - if (lockMode != null) { - session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity); - } - return null; - }); - } - - @Override - public void saveOrUpdate(Object entity) throws DataAccessException { - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - session.saveOrUpdate(entity); - return null; - }); - } - - @Override - public void saveOrUpdate(String entityName, Object entity) throws DataAccessException { - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - session.saveOrUpdate(entityName, entity); - return null; - }); - } - - @Override - public void replicate(Object entity, ReplicationMode replicationMode) throws DataAccessException { - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - session.replicate(entity, replicationMode); - return null; - }); - } - - @Override - public void replicate(String entityName, Object entity, ReplicationMode replicationMode) - throws DataAccessException { - - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - session.replicate(entityName, entity, replicationMode); - return null; - }); - } - - @Override - public void persist(Object entity) throws DataAccessException { - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - session.persist(entity); - return null; - }); - } - - @Override - public void persist(String entityName, Object entity) throws DataAccessException { - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - session.persist(entityName, entity); - return null; - }); - } - - @Override - @SuppressWarnings("unchecked") - public T merge(T entity) throws DataAccessException { - return nonNull(executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - return (T) session.merge(entity); - })); - } - - @Override - @SuppressWarnings("unchecked") - public T merge(String entityName, T entity) throws DataAccessException { - return nonNull(executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - return (T) session.merge(entityName, entity); - })); - } - - @Override - public void delete(Object entity) throws DataAccessException { - delete(entity, null); - } - - @Override - public void delete(Object entity, @Nullable LockMode lockMode) throws DataAccessException { - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - if (lockMode != null) { - session.buildLockRequest(new LockOptions(lockMode)).lock(entity); - } - session.delete(entity); - return null; - }); - } - - @Override - public void delete(String entityName, Object entity) throws DataAccessException { - delete(entityName, entity, null); - } - - @Override - public void delete(String entityName, Object entity, @Nullable LockMode lockMode) - throws DataAccessException { - - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - if (lockMode != null) { - session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity); - } - session.delete(entityName, entity); - return null; - }); - } - - @Override - public void deleteAll(Collection entities) throws DataAccessException { - executeWithNativeSession(session -> { - checkWriteOperationAllowed(session); - for (Object entity : entities) { - session.delete(entity); - } - return null; - }); - } - - @Override - public void flush() throws DataAccessException { - executeWithNativeSession(session -> { - session.flush(); - return null; - }); - } - - @Override - public void clear() throws DataAccessException { - executeWithNativeSession(session -> { - session.clear(); - return null; - }); - } - - - //------------------------------------------------------------------------- - // Convenience finder methods for detached criteria - //------------------------------------------------------------------------- - - @Override - public List findByCriteria(DetachedCriteria criteria) throws DataAccessException { - return findByCriteria(criteria, -1, -1); - } - - @Override - public List findByCriteria(DetachedCriteria criteria, int firstResult, int maxResults) - throws DataAccessException { - - Assert.notNull(criteria, "DetachedCriteria must not be null"); - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Criteria executableCriteria = criteria.getExecutableCriteria(session); - prepareCriteria(executableCriteria); - if (firstResult >= 0) { - executableCriteria.setFirstResult(firstResult); - } - if (maxResults > 0) { - executableCriteria.setMaxResults(maxResults); - } - return executableCriteria.list(); - })); - } - - @Override - public List findByExample(T exampleEntity) throws DataAccessException { - return findByExample(null, exampleEntity, -1, -1); - } - - @Override - public List findByExample(String entityName, T exampleEntity) throws DataAccessException { - return findByExample(entityName, exampleEntity, -1, -1); - } - - @Override - public List findByExample(T exampleEntity, int firstResult, int maxResults) throws DataAccessException { - return findByExample(null, exampleEntity, firstResult, maxResults); - } - - @Override - @SuppressWarnings({"unchecked", "deprecation"}) - public List findByExample(@Nullable String entityName, T exampleEntity, int firstResult, int maxResults) - throws DataAccessException { - - Assert.notNull(exampleEntity, "Example entity must not be null"); - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Criteria executableCriteria = (entityName != null ? - session.createCriteria(entityName) : session.createCriteria(exampleEntity.getClass())); - executableCriteria.add(Example.create(exampleEntity)); - prepareCriteria(executableCriteria); - if (firstResult >= 0) { - executableCriteria.setFirstResult(firstResult); - } - if (maxResults > 0) { - executableCriteria.setMaxResults(maxResults); - } - return executableCriteria.list(); - })); - } - - - //------------------------------------------------------------------------- - // Convenience finder methods for HQL strings - //------------------------------------------------------------------------- - - @Deprecated - @Override - public List find(String queryString, @Nullable Object... values) throws DataAccessException { - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Query queryObject = session.createQuery(queryString); - prepareQuery(queryObject); - if (values != null) { - for (int i = 0; i < values.length; i++) { - queryObject.setParameter(i, values[i]); - } - } - return queryObject.list(); - })); - } - - @Deprecated - @Override - public List findByNamedParam(String queryString, String paramName, Object value) - throws DataAccessException { - - return findByNamedParam(queryString, new String[] {paramName}, new Object[] {value}); - } - - @Deprecated - @Override - public List findByNamedParam(String queryString, String[] paramNames, Object[] values) - throws DataAccessException { - - if (paramNames.length != values.length) { - throw new IllegalArgumentException("Length of paramNames array must match length of values array"); - } - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Query queryObject = session.createQuery(queryString); - prepareQuery(queryObject); - for (int i = 0; i < values.length; i++) { - applyNamedParameterToQuery(queryObject, paramNames[i], values[i]); - } - return queryObject.list(); - })); - } - - @Deprecated - @Override - public List findByValueBean(String queryString, Object valueBean) throws DataAccessException { - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Query queryObject = session.createQuery(queryString); - prepareQuery(queryObject); - queryObject.setProperties(valueBean); - return queryObject.list(); - })); - } - - - //------------------------------------------------------------------------- - // Convenience finder methods for named queries - //------------------------------------------------------------------------- - - @Deprecated - @Override - public List findByNamedQuery(String queryName, @Nullable Object... values) throws DataAccessException { - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Query queryObject = session.getNamedQuery(queryName); - prepareQuery(queryObject); - if (values != null) { - for (int i = 0; i < values.length; i++) { - queryObject.setParameter(i, values[i]); - } - } - return queryObject.list(); - })); - } - - @Deprecated - @Override - public List findByNamedQueryAndNamedParam(String queryName, String paramName, Object value) - throws DataAccessException { - - return findByNamedQueryAndNamedParam(queryName, new String[] {paramName}, new Object[] {value}); - } - - @Deprecated - @Override - @SuppressWarnings("NullAway") - public List findByNamedQueryAndNamedParam( - String queryName, @Nullable String[] paramNames, @Nullable Object[] values) - throws DataAccessException { - - if (values != null && (paramNames == null || paramNames.length != values.length)) { - throw new IllegalArgumentException("Length of paramNames array must match length of values array"); - } - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Query queryObject = session.getNamedQuery(queryName); - prepareQuery(queryObject); - if (values != null) { - for (int i = 0; i < values.length; i++) { - applyNamedParameterToQuery(queryObject, paramNames[i], values[i]); - } - } - return queryObject.list(); - })); - } - - @Deprecated - @Override - public List findByNamedQueryAndValueBean(String queryName, Object valueBean) throws DataAccessException { - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Query queryObject = session.getNamedQuery(queryName); - prepareQuery(queryObject); - queryObject.setProperties(valueBean); - return queryObject.list(); - })); - } - - - //------------------------------------------------------------------------- - // Convenience query methods for iteration and bulk updates/deletes - //------------------------------------------------------------------------- - - @SuppressWarnings("deprecation") - @Deprecated - @Override - public Iterator iterate(String queryString, @Nullable Object... values) throws DataAccessException { - return nonNull(executeWithNativeSession((HibernateCallback>) session -> { - Query queryObject = session.createQuery(queryString); - prepareQuery(queryObject); - if (values != null) { - for (int i = 0; i < values.length; i++) { - queryObject.setParameter(i, values[i]); - } - } - return queryObject.iterate(); - })); - } - - @Deprecated - @Override - public void closeIterator(Iterator it) throws DataAccessException { - try { - Hibernate.close(it); - } - catch (HibernateException ex) { - throw SessionFactoryUtils.convertHibernateAccessException(ex); - } - } - - @Deprecated - @Override - public int bulkUpdate(String queryString, @Nullable Object... values) throws DataAccessException { - Integer result = executeWithNativeSession(session -> { - Query queryObject = session.createQuery(queryString); - prepareQuery(queryObject); - if (values != null) { - for (int i = 0; i < values.length; i++) { - queryObject.setParameter(i, values[i]); - } - } - return queryObject.executeUpdate(); - }); - Assert.state(result != null, "No update count"); - return result; - } - - - //------------------------------------------------------------------------- - // Helper methods used by the operations above - //------------------------------------------------------------------------- - - /** - * Check whether write operations are allowed on the given Session. - *

Default implementation throws an InvalidDataAccessApiUsageException in - * case of {@code FlushMode.MANUAL}. Can be overridden in subclasses. - * @param session current Hibernate Session - * @throws InvalidDataAccessApiUsageException if write operations are not allowed - * @see #setCheckWriteOperations - * @see Session#getFlushMode() - * @see FlushMode#MANUAL - */ - protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException { - if (isCheckWriteOperations() && session.getHibernateFlushMode().lessThan(FlushMode.COMMIT)) { - throw new InvalidDataAccessApiUsageException( - "Write operations are not allowed in read-only mode (FlushMode.MANUAL): "+ - "Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition."); - } - } - - /** - * Prepare the given Criteria object, applying cache settings and/or - * a transaction timeout. - * @param criteria the Criteria object to prepare - * @see #setCacheQueries - * @see #setQueryCacheRegion - */ - protected void prepareCriteria(Criteria criteria) { - if (isCacheQueries()) { - criteria.setCacheable(true); - if (getQueryCacheRegion() != null) { - criteria.setCacheRegion(getQueryCacheRegion()); - } - } - if (getFetchSize() > 0) { - criteria.setFetchSize(getFetchSize()); - } - if (getMaxResults() > 0) { - criteria.setMaxResults(getMaxResults()); - } - - ResourceHolderSupport sessionHolder = - (ResourceHolderSupport) TransactionSynchronizationManager.getResource(obtainSessionFactory()); - if (sessionHolder != null && sessionHolder.hasTimeout()) { - criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds()); - } - } - - /** - * Prepare the given Query object, applying cache settings and/or - * a transaction timeout. - * @param queryObject the Query object to prepare - * @see #setCacheQueries - * @see #setQueryCacheRegion - */ - protected void prepareQuery(Query queryObject) { - if (isCacheQueries()) { - queryObject.setCacheable(true); - if (getQueryCacheRegion() != null) { - queryObject.setCacheRegion(getQueryCacheRegion()); - } - } - if (getFetchSize() > 0) { - queryObject.setFetchSize(getFetchSize()); - } - if (getMaxResults() > 0) { - queryObject.setMaxResults(getMaxResults()); - } - - ResourceHolderSupport sessionHolder = - (ResourceHolderSupport) TransactionSynchronizationManager.getResource(obtainSessionFactory()); - if (sessionHolder != null && sessionHolder.hasTimeout()) { - queryObject.setTimeout(sessionHolder.getTimeToLiveInSeconds()); - } - } - - /** - * Apply the given name parameter to the given Query object. - * @param queryObject the Query object - * @param paramName the name of the parameter - * @param value the value of the parameter - * @throws HibernateException if thrown by the Query object - */ - protected void applyNamedParameterToQuery(Query queryObject, String paramName, Object value) - throws HibernateException { - - if (value instanceof Collection collection) { - queryObject.setParameterList(paramName, collection); - } - else if (value instanceof Object[] array) { - queryObject.setParameterList(paramName, array); - } - else { - queryObject.setParameter(paramName, value); - } - } - - private static T nonNull(@Nullable T result) { - Assert.state(result != null, "No result"); - return result; - } - - - /** - * Invocation handler that suppresses close calls on Hibernate Sessions. - * Also prepares returned Query and Criteria objects. - * @see Session#close - */ - private class CloseSuppressingInvocationHandler implements InvocationHandler { - - private final Session target; - - public CloseSuppressingInvocationHandler(Session target) { - this.target = target; - } - - @Override - @Nullable - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // Invocation on Session interface coming in... - - return switch (method.getName()) { - // Only consider equal when proxies are identical. - case "equals" -> (proxy == args[0]); - // Use hashCode of Session proxy. - case "hashCode" -> System.identityHashCode(proxy); - // Handle close method: suppress, not valid. - case "close" -> null; - default -> { - try { - // Invoke method on target Session. - Object retVal = method.invoke(this.target, args); - - // If return value is a Query or Criteria, apply transaction timeout. - // Applies to createQuery, getNamedQuery, createCriteria. - if (retVal instanceof Criteria criteria) { - prepareCriteria(criteria); - } - else if (retVal instanceof Query query) { - prepareQuery(query); - } - - yield retVal; - } - catch (InvocationTargetException ex) { - throw ex.getTargetException(); - } - } - }; - } - } - -} diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java index 94517a0a2a0..f0ee7c9f91c 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java @@ -121,10 +121,10 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator private RegionFactory cacheRegionFactory; @Nullable - private MultiTenantConnectionProvider multiTenantConnectionProvider; + private MultiTenantConnectionProvider multiTenantConnectionProvider; @Nullable - private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; + private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; @Nullable private Properties hibernateProperties; @@ -312,7 +312,7 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator * @since 4.3 * @see LocalSessionFactoryBuilder#setMultiTenantConnectionProvider */ - public void setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) { + public void setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) { this.multiTenantConnectionProvider = multiTenantConnectionProvider; } @@ -320,7 +320,7 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator * Set a {@link CurrentTenantIdentifierResolver} to be passed on to the SessionFactory. * @see LocalSessionFactoryBuilder#setCurrentTenantIdentifierResolver */ - public void setCurrentTenantIdentifierResolver(CurrentTenantIdentifierResolver currentTenantIdentifierResolver) { + public void setCurrentTenantIdentifierResolver(CurrentTenantIdentifierResolver currentTenantIdentifierResolver) { this.currentTenantIdentifierResolver = currentTenantIdentifierResolver; } diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java index 764e8f97d9a..074f1028535 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -169,7 +169,7 @@ public class LocalSessionFactoryBuilder extends Configuration { getProperties().put(AvailableSettings.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName()); if (dataSource != null) { - getProperties().put(AvailableSettings.DATASOURCE, dataSource); + getProperties().put(AvailableSettings.JAKARTA_NON_JTA_DATASOURCE, dataSource); } getProperties().put(AvailableSettings.CONNECTION_HANDLING, PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_HOLD); @@ -256,7 +256,7 @@ public class LocalSessionFactoryBuilder extends Configuration { * @since 4.3 * @see AvailableSettings#MULTI_TENANT_CONNECTION_PROVIDER */ - public LocalSessionFactoryBuilder setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) { + public LocalSessionFactoryBuilder setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) { getProperties().put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider); return this; } @@ -267,9 +267,10 @@ public class LocalSessionFactoryBuilder extends Configuration { * @see AvailableSettings#MULTI_TENANT_IDENTIFIER_RESOLVER */ @Override - public void setCurrentTenantIdentifierResolver(CurrentTenantIdentifierResolver currentTenantIdentifierResolver) { + public LocalSessionFactoryBuilder setCurrentTenantIdentifierResolver(CurrentTenantIdentifierResolver currentTenantIdentifierResolver) { getProperties().put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver); super.setCurrentTenantIdentifierResolver(currentTenantIdentifierResolver); + return this; } /** diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/SessionFactoryUtils.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/SessionFactoryUtils.java index 9719081da3d..a5283976283 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/SessionFactoryUtils.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/SessionFactoryUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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,7 +16,6 @@ package org.springframework.orm.hibernate5; -import java.lang.reflect.Method; import java.util.Map; import javax.sql.DataSource; @@ -64,8 +63,6 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.dao.PessimisticLockingFailureException; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.lang.Nullable; -import org.springframework.util.ClassUtils; -import org.springframework.util.ReflectionUtils; /** * Helper class featuring methods for Hibernate Session handling. @@ -151,14 +148,11 @@ public abstract class SessionFactoryUtils { */ @Nullable public static DataSource getDataSource(SessionFactory sessionFactory) { - Method getProperties = ClassUtils.getMethodIfAvailable(sessionFactory.getClass(), "getProperties"); - if (getProperties != null) { - Map props = (Map) ReflectionUtils.invokeMethod(getProperties, sessionFactory); - if (props != null) { - Object dataSourceValue = props.get(Environment.DATASOURCE); - if (dataSourceValue instanceof DataSource dataSource) { - return dataSource; - } + Map props = sessionFactory.getProperties(); + if (props != null) { + Object dataSourceValue = props.get(Environment.JAKARTA_NON_JTA_DATASOURCE); + if (dataSourceValue instanceof DataSource dataSource) { + return dataSource; } } if (sessionFactory instanceof SessionFactoryImplementor sfi) { diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/support/HibernateDaoSupport.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/support/HibernateDaoSupport.java deleted file mode 100644 index 965334421df..00000000000 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/support/HibernateDaoSupport.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://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.orm.hibernate5.support; - -import org.hibernate.Session; -import org.hibernate.SessionFactory; - -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.dao.support.DaoSupport; -import org.springframework.lang.Nullable; -import org.springframework.orm.hibernate5.HibernateTemplate; -import org.springframework.util.Assert; - -/** - * Convenient superclass for Hibernate-based data access objects. - * - *

Requires a {@link SessionFactory} to be set, providing a - * {@link org.springframework.orm.hibernate5.HibernateTemplate} based on it to - * subclasses through the {@link #getHibernateTemplate()} method. - * Can alternatively be initialized directly with a HibernateTemplate, - * in order to reuse the latter's settings such as the SessionFactory, - * exception translator, flush mode, etc. - * - *

This class will create its own HibernateTemplate instance if a SessionFactory - * is passed in. The "allowCreate" flag on that HibernateTemplate will be "true" - * by default. A custom HibernateTemplate instance can be used through overriding - * {@link #createHibernateTemplate}. - * - *

NOTE: Hibernate access code can also be coded in plain Hibernate style. - * Hence, for newly started projects, consider adopting the standard Hibernate - * style of coding data access objects instead, based on - * {@link SessionFactory#getCurrentSession()}. - * This HibernateTemplate primarily exists as a migration helper for Hibernate 3 - * based data access code, to benefit from bug fixes in Hibernate 5.x. - * - * @author Juergen Hoeller - * @since 4.2 - * @see #setSessionFactory - * @see #getHibernateTemplate - * @see org.springframework.orm.hibernate5.HibernateTemplate - */ -public abstract class HibernateDaoSupport extends DaoSupport { - - @Nullable - private HibernateTemplate hibernateTemplate; - - - /** - * Set the Hibernate SessionFactory to be used by this DAO. - * Will automatically create a HibernateTemplate for the given SessionFactory. - * @see #createHibernateTemplate - * @see #setHibernateTemplate - */ - public final void setSessionFactory(SessionFactory sessionFactory) { - if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) { - this.hibernateTemplate = createHibernateTemplate(sessionFactory); - } - } - - /** - * Create a HibernateTemplate for the given SessionFactory. - * Only invoked if populating the DAO with a SessionFactory reference! - *

Can be overridden in subclasses to provide a HibernateTemplate instance - * with different configuration, or a custom HibernateTemplate subclass. - * @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for - * @return the new HibernateTemplate instance - * @see #setSessionFactory - */ - protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) { - return new HibernateTemplate(sessionFactory); - } - - /** - * Return the Hibernate SessionFactory used by this DAO. - */ - @Nullable - public final SessionFactory getSessionFactory() { - return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null); - } - - /** - * Set the HibernateTemplate for this DAO explicitly, - * as an alternative to specifying a SessionFactory. - * @see #setSessionFactory - */ - public final void setHibernateTemplate(@Nullable HibernateTemplate hibernateTemplate) { - this.hibernateTemplate = hibernateTemplate; - } - - /** - * Return the HibernateTemplate for this DAO, - * pre-initialized with the SessionFactory or set explicitly. - *

Note: The returned HibernateTemplate is a shared instance. - * You may introspect its configuration, but not modify the configuration - * (other than from within an {@link #initDao} implementation). - * Consider creating a custom HibernateTemplate instance via - * {@code new HibernateTemplate(getSessionFactory())}, in which case - * you're allowed to customize the settings on the resulting instance. - */ - @Nullable - public final HibernateTemplate getHibernateTemplate() { - return this.hibernateTemplate; - } - - @Override - protected final void checkDaoConfig() { - if (this.hibernateTemplate == null) { - throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required"); - } - } - - - /** - * Conveniently obtain the current Hibernate Session. - * @return the Hibernate Session - * @throws DataAccessResourceFailureException if the Session couldn't be created - * @see SessionFactory#getCurrentSession() - */ - protected final Session currentSession() throws DataAccessResourceFailureException { - SessionFactory sessionFactory = getSessionFactory(); - Assert.state(sessionFactory != null, "No SessionFactory set"); - return sessionFactory.getCurrentSession(); - } - -} diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java b/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java index 6acec2dfa54..3d31c1f7554 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -192,6 +192,7 @@ public abstract class ExtendedEntityManagerCreator { * transactions (according to the JPA 2.1 SynchronizationType rules) * @return the EntityManager proxy */ + @SuppressWarnings("removal") private static EntityManager createProxy(EntityManager rawEntityManager, EntityManagerFactoryInfo emfInfo, boolean containerManaged, boolean synchronizedWithTransaction) { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java index 7bd5304b006..2393c67fae5 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java @@ -45,6 +45,7 @@ import org.springframework.util.ClassUtils; * @author Costin Leau * @since 2.0 */ +@SuppressWarnings("removal") public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo { @Nullable @@ -289,6 +290,18 @@ public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo { throw new UnsupportedOperationException("getNewTempClassLoader not supported"); } + @Override + @Nullable + public String getScopeAnnotationName() { + return null; + } + + @Override + @Nullable + public List getQualifierAnnotationNames() { + return null; + } + @Override public String toString() { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java index 5da0ac9866e..89800bdae4f 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java @@ -21,6 +21,7 @@ import java.util.List; import javax.lang.model.element.Modifier; +import jakarta.persistence.AttributeConverter; import jakarta.persistence.Convert; import jakarta.persistence.Converter; import jakarta.persistence.EntityListeners; @@ -173,7 +174,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr } ReflectionUtils.doWithFields(managedClass, field -> { Convert convertFieldAnnotation = AnnotationUtils.findAnnotation(field, Convert.class); - if (convertFieldAnnotation != null && convertFieldAnnotation.converter() != void.class) { + if (convertFieldAnnotation != null && convertFieldAnnotation.converter() != AttributeConverter.class) { reflectionHints.registerType(convertFieldAnnotation.converter(), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); } }); diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java index 85fd8d7823f..22f6d057a11 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java @@ -185,6 +185,7 @@ final class PersistenceUnitReader { /** * Parse the unit info DOM element. */ + @SuppressWarnings("removal") SpringPersistenceUnitInfo parsePersistenceUnitInfo( Element persistenceUnit, String version, @Nullable URL rootUrl) throws IOException { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java index 6f601c1ce80..52044289441 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java @@ -28,22 +28,17 @@ import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.DB2Dialect; -import org.hibernate.dialect.DerbyTenSevenDialect; import org.hibernate.dialect.H2Dialect; -import org.hibernate.dialect.HANAColumnStoreDialect; +import org.hibernate.dialect.HANADialect; import org.hibernate.dialect.HSQLDialect; -import org.hibernate.dialect.Informix10Dialect; -import org.hibernate.dialect.MySQL57Dialect; import org.hibernate.dialect.MySQLDialect; -import org.hibernate.dialect.Oracle12cDialect; -import org.hibernate.dialect.PostgreSQL95Dialect; -import org.hibernate.dialect.SQLServer2012Dialect; +import org.hibernate.dialect.OracleDialect; +import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.dialect.SybaseDialect; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.springframework.lang.Nullable; -import org.springframework.util.ClassUtils; /** * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate. @@ -72,9 +67,6 @@ import org.springframework.util.ClassUtils; */ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { - private static final boolean oldDialectsPresent = ClassUtils.isPresent( - "org.hibernate.dialect.PostgreSQL95Dialect", HibernateJpaVendorAdapter.class.getClassLoader()); - private final HibernateJpaDialect jpaDialect = new HibernateJpaDialect(); private final PersistenceProvider persistenceProvider; @@ -129,6 +121,7 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { return "org.hibernate"; } + @SuppressWarnings("removal") @Override public Map getJpaPropertyMap(PersistenceUnitInfo pui) { return buildJpaPropertyMap(this.jpaDialect.prepareConnection && @@ -151,6 +144,12 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { if (databaseDialectClass != null) { jpaProperties.put(AvailableSettings.DIALECT, databaseDialectClass.getName()); } + else { + String databaseDialectName = determineDatabaseDialectName(getDatabase()); + if (databaseDialectName != null) { + jpaProperties.put(AvailableSettings.DIALECT, databaseDialectName); + } + } } if (isGenerateDdl()) { @@ -173,43 +172,41 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { /** * Determine the Hibernate database dialect class for the given target database. + *

The default implementation covers the common built-in dialects. * @param database the target database * @return the Hibernate database dialect class, or {@code null} if none found + * @see #determineDatabaseDialectName */ - @SuppressWarnings("deprecation") // for OracleDialect on Hibernate 5.6 and DerbyDialect/PostgreSQLDialect on Hibernate 6.2 @Nullable protected Class determineDatabaseDialectClass(Database database) { - if (oldDialectsPresent) { // Hibernate <6.2 - return switch (database) { - case DB2 -> DB2Dialect.class; - case DERBY -> DerbyTenSevenDialect.class; - case H2 -> H2Dialect.class; - case HANA -> HANAColumnStoreDialect.class; - case HSQL -> HSQLDialect.class; - case INFORMIX -> Informix10Dialect.class; - case MYSQL -> MySQL57Dialect.class; - case ORACLE -> Oracle12cDialect.class; - case POSTGRESQL -> PostgreSQL95Dialect.class; - case SQL_SERVER -> SQLServer2012Dialect.class; - case SYBASE -> SybaseDialect.class; - default -> null; - }; - } - else { // Hibernate 6.2+ aligned - return switch (database) { - case DB2 -> DB2Dialect.class; - case DERBY -> org.hibernate.dialect.DerbyDialect.class; - case H2 -> H2Dialect.class; - case HANA -> HANAColumnStoreDialect.class; - case HSQL -> HSQLDialect.class; - case MYSQL -> MySQLDialect.class; - case ORACLE -> org.hibernate.dialect.OracleDialect.class; - case POSTGRESQL -> org.hibernate.dialect.PostgreSQLDialect.class; - case SQL_SERVER -> SQLServerDialect.class; - case SYBASE -> SybaseDialect.class; - default -> null; - }; - } + return switch (database) { + case DB2 -> DB2Dialect.class; + case H2 -> H2Dialect.class; + case HANA -> HANADialect.class; + case HSQL -> HSQLDialect.class; + case MYSQL -> MySQLDialect.class; + case ORACLE -> OracleDialect.class; + case POSTGRESQL -> PostgreSQLDialect.class; + case SQL_SERVER -> SQLServerDialect.class; + case SYBASE -> SybaseDialect.class; + default -> null; + }; + } + + /** + * Determine the Hibernate database dialect class name for the given target database. + *

The default implementation covers the common community dialect for Derby. + * @param database the target database + * @return the Hibernate database dialect class name, or {@code null} if none found + * @since 7.0 + * @see #determineDatabaseDialectClass + */ + @Nullable + protected String determineDatabaseDialectName(Database database) { + return switch (database) { + case DERBY -> "org.hibernate.community.dialect.DerbyDialect"; + default -> null; + }; } @Override diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBeanTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBeanTests.java index a31b2e646c3..0752469e060 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBeanTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBeanTests.java @@ -23,6 +23,7 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.EntityTransaction; import jakarta.persistence.OptimisticLockException; +import jakarta.persistence.PersistenceConfiguration; import jakarta.persistence.PersistenceException; import jakarta.persistence.spi.PersistenceProvider; import jakarta.persistence.spi.PersistenceUnitInfo; @@ -52,7 +53,7 @@ import static org.mockito.Mockito.verify; * @author Juergen Hoeller * @author Phillip Webb */ -@SuppressWarnings("rawtypes") +@SuppressWarnings({"rawtypes", "removal"}) class LocalContainerEntityManagerFactoryBeanTests extends AbstractEntityManagerFactoryBeanTests { // Static fields set by inner class DummyPersistenceProvider @@ -310,6 +311,11 @@ class LocalContainerEntityManagerFactoryBeanTests extends AbstractEntityManagerF throw new UnsupportedOperationException(); } + @Override + public EntityManagerFactory createEntityManagerFactory(PersistenceConfiguration persistenceConfiguration) { + throw new UnsupportedOperationException(); + } + @Override public ProviderUtil getProviderUtil() { throw new UnsupportedOperationException(); @@ -357,6 +363,15 @@ class LocalContainerEntityManagerFactoryBeanTests extends AbstractEntityManagerF public boolean isActive() { return false; } + + @Override + public void setTimeout(Integer integer) { + } + + @Override + public Integer getTimeout() { + return null; + } } } diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBeanTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBeanTests.java index 81e2125b5db..379ecea804c 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBeanTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBeanTests.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.Properties; import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.PersistenceConfiguration; import jakarta.persistence.spi.PersistenceProvider; import jakarta.persistence.spi.PersistenceUnitInfo; import jakarta.persistence.spi.ProviderUtil; @@ -97,6 +98,11 @@ class LocalEntityManagerFactoryBeanTests extends AbstractEntityManagerFactoryBea return mockEmf; } + @Override + public EntityManagerFactory createEntityManagerFactory(PersistenceConfiguration persistenceConfiguration) { + throw new UnsupportedOperationException(); + } + @Override public ProviderUtil getProviderUtil() { throw new UnsupportedOperationException(); diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/domain2/package-info.java b/spring-orm/src/test/java/org/springframework/orm/jpa/domain2/package-info.java index cc701bff02a..c302d958010 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/domain2/package-info.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/domain2/package-info.java @@ -1,7 +1,8 @@ /** * Sample package-info for testing purposes. */ -@TypeDef(name = "test", typeClass = Object.class) +@TypeRegistration(basicClass = Object.class, userType = UserTypeLegacyBridge.class) package org.springframework.orm.jpa.domain2; -import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeRegistration; +import org.hibernate.usertype.UserTypeLegacyBridge; diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java index b4069e6ba90..3801d9ec570 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java @@ -21,7 +21,7 @@ import java.util.function.Consumer; import javax.sql.DataSource; -import org.hibernate.tuple.CreationTimestampGeneration; +import org.hibernate.annotations.CreationTimestamp; import org.junit.jupiter.api.Test; import org.springframework.aot.hint.MemberCategory; @@ -108,12 +108,12 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { }); } - @Test + // @Test void contributeHibernateHints() { GenericApplicationContext context = new AnnotationConfigApplicationContext(); context.registerBean(HibernateDomainConfiguration.class); contributeHints(context, hints -> - assertThat(RuntimeHintsPredicates.reflection().onType(CreationTimestampGeneration.class) + assertThat(RuntimeHintsPredicates.reflection().onType(CreationTimestamp.class) .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints)); } @@ -144,6 +144,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { result.accept(generationContext.getRuntimeHints()); } + public static class JpaDomainConfiguration extends AbstractEntityManagerWithPackagesToScanConfiguration { @Override @@ -152,6 +153,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { } } + public static class HibernateDomainConfiguration extends AbstractEntityManagerWithPackagesToScanConfiguration { @Override @@ -160,6 +162,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { } } + public abstract static class AbstractEntityManagerWithPackagesToScanConfiguration { protected boolean scanningInvoked; @@ -194,7 +197,6 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { } protected abstract String packageToScan(); - } } diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceXmlParsingTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceXmlParsingTests.java index c0c66f1ce1b..80c9fd987e9 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceXmlParsingTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceXmlParsingTests.java @@ -47,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThatRuntimeException; * @author Juergen Hoeller * @author Nicholas Williams */ +@SuppressWarnings("removal") class PersistenceXmlParsingTests { @Test diff --git a/spring-test/spring-test.gradle b/spring-test/spring-test.gradle index f0bc5a7f635..b84e77f76fb 100644 --- a/spring-test/spring-test.gradle +++ b/spring-test/spring-test.gradle @@ -27,7 +27,6 @@ dependencies { optional("jakarta.websocket:jakarta.websocket-api") optional("jakarta.websocket:jakarta.websocket-client-api") optional("jakarta.xml.bind:jakarta.xml.bind-api") - optional("javax.inject:javax.inject") optional("junit:junit") optional("org.apache.groovy:groovy") optional("org.apache.tomcat.embed:tomcat-embed-core") @@ -78,7 +77,7 @@ dependencies { } testImplementation("org.awaitility:awaitility") testImplementation("org.easymock:easymock") - testImplementation("org.hibernate:hibernate-core-jakarta") + testImplementation("org.hibernate:hibernate-core") testImplementation("org.hibernate:hibernate-validator") testImplementation("org.hsqldb:hsqldb") testImplementation("org.junit.platform:junit-platform-testkit") diff --git a/spring-test/src/main/java/org/springframework/test/context/TestConstructor.java b/spring-test/src/main/java/org/springframework/test/context/TestConstructor.java index 3285ca6f5ac..d140bc26955 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestConstructor.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestConstructor.java @@ -39,9 +39,8 @@ import org.springframework.lang.Nullable; * on a test class, the default test constructor autowire mode will be * used. See {@link #TEST_CONSTRUCTOR_AUTOWIRE_MODE_PROPERTY_NAME} for details on * how to change the default mode. Note, however, that a local declaration of - * {@link org.springframework.beans.factory.annotation.Autowired @Autowired} - * {@link jakarta.inject.Inject @jakarta.inject.Inject}, or - * {@link javax.inject.Inject @javax.inject.Inject} on a constructor takes + * {@link org.springframework.beans.factory.annotation.Autowired @Autowired} or + * {@link jakarta.inject.Inject @jakarta.inject.Inject} on a constructor takes * precedence over both {@code @TestConstructor} and the default mode. * *

This annotation may be used as a meta-annotation to create custom @@ -63,7 +62,6 @@ import org.springframework.lang.Nullable; * @since 5.2 * @see org.springframework.beans.factory.annotation.Autowired @Autowired * @see jakarta.inject.Inject @jakarta.inject.Inject - * @see javax.inject.Inject @javax.inject.Inject * @see org.springframework.test.context.junit.jupiter.SpringExtension SpringExtension * @see org.springframework.test.context.junit.jupiter.SpringJUnitConfig @SpringJUnitConfig * @see org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig @SpringJUnitWebConfig @@ -109,7 +107,6 @@ public @interface TestConstructor { * @see #TEST_CONSTRUCTOR_AUTOWIRE_MODE_PROPERTY_NAME * @see org.springframework.beans.factory.annotation.Autowired @Autowired * @see jakarta.inject.Inject @jakarta.inject.Inject - * @see javax.inject.Inject @javax.inject.Inject * @see AutowireMode#ALL * @see AutowireMode#ANNOTATED */ @@ -126,9 +123,8 @@ public @interface TestConstructor { /** * All test constructor parameters will be autowired as if the constructor * itself were annotated with - * {@link org.springframework.beans.factory.annotation.Autowired @Autowired}, - * {@link jakarta.inject.Inject @jakarta.inject.Inject}, or - * {@link javax.inject.Inject @javax.inject.Inject}. + * {@link org.springframework.beans.factory.annotation.Autowired @Autowired} or + * {@link jakarta.inject.Inject @jakarta.inject.Inject}. * @see #ANNOTATED */ ALL, @@ -140,9 +136,8 @@ public @interface TestConstructor { * {@link org.springframework.beans.factory.annotation.Qualifier @Qualifier}, * or {@link org.springframework.beans.factory.annotation.Value @Value}, * or if the constructor itself is annotated with - * {@link org.springframework.beans.factory.annotation.Autowired @Autowired}, - * {@link jakarta.inject.Inject @jakarta.inject.Inject}, or - * {@link javax.inject.Inject @javax.inject.Inject}. + * {@link org.springframework.beans.factory.annotation.Autowired @Autowired} or + * {@link jakarta.inject.Inject @jakarta.inject.Inject}. * @see #ALL */ ANNOTATED; diff --git a/spring-test/src/main/java/org/springframework/test/context/support/TestConstructorUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/TestConstructorUtils.java index b2dfa370754..37ddd684708 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/TestConstructorUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/TestConstructorUtils.java @@ -63,15 +63,6 @@ public abstract class TestConstructorUtils { catch (ClassNotFoundException ex) { // jakarta.inject API not available - simply skip. } - - try { - autowiredAnnotationTypes.add((Class) - ClassUtils.forName("javax.inject.Inject", classLoader)); - logger.trace("'javax.inject.Inject' annotation found and supported for autowiring"); - } - catch (ClassNotFoundException ex) { - // javax.inject API not available - simply skip. - } } @@ -135,9 +126,8 @@ public abstract class TestConstructorUtils { * conditions is {@code true}. * *

    - *
  1. The constructor is annotated with {@link Autowired @Autowired}, - * {@link jakarta.inject.Inject @jakarta.inject.Inject}, or - * {@link javax.inject.Inject @javax.inject.Inject}.
  2. + *
  3. The constructor is annotated with {@link Autowired @Autowired} or + * {@link jakarta.inject.Inject @jakarta.inject.Inject}.
  4. *
  5. {@link TestConstructor @TestConstructor} is present or * meta-present on the test class with * {@link TestConstructor#autowireMode() autowireMode} set to diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnitJupiterAutowiredConstructorInjectionTests.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnitJupiterAutowiredConstructorInjectionTests.java index 65a0c8d6b68..1efa38760da 100644 --- a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnitJupiterAutowiredConstructorInjectionTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/SpringJUnitJupiterAutowiredConstructorInjectionTests.java @@ -57,15 +57,6 @@ class SpringJUnitJupiterAutowiredConstructorInjectionTests { } } - @Nested - class JavaxInjectTests extends BaseClass { - - @javax.inject.Inject - JavaxInjectTests(ApplicationContext context, Person dilbert, Dog dog, @Value("${enigma}") Integer enigma) { - super(context, dilbert, dog, enigma); - } - } - @SpringJUnitConfig(TestConfig.class) @TestPropertySource(properties = "enigma = 42") diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests.java index 54f2177dc95..c4266dd46e5 100644 --- a/spring-test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests.java @@ -16,7 +16,6 @@ package org.springframework.test.context.junit4.orm; -import jakarta.persistence.PersistenceException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.exception.ConstraintViolationException; @@ -115,16 +114,8 @@ public class HibernateSessionFlushingTests extends AbstractTransactionalJUnit4Sp @Test public void updateSamWithNullDriversLicenseWithSessionFlush() { updateSamWithNullDriversLicense(); - assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> { - // Manual flush is required to avoid false positive in test - try { - sessionFactory.getCurrentSession().flush(); - } - catch (PersistenceException ex) { - // Wrapped in Hibernate 5.2, with the constraint violation as cause - throw ex.getCause(); - } - }); + // Manual flush is required to avoid false positive in test + assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(sessionFactory.getCurrentSession()::flush); } private void updateSamWithNullDriversLicense() { diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/orm/repository/hibernate/HibernatePersonRepository.java b/spring-test/src/test/java/org/springframework/test/context/junit4/orm/repository/hibernate/HibernatePersonRepository.java index 317ec5a5fdc..9c5c0f84f7b 100644 --- a/spring-test/src/test/java/org/springframework/test/context/junit4/orm/repository/hibernate/HibernatePersonRepository.java +++ b/spring-test/src/test/java/org/springframework/test/context/junit4/orm/repository/hibernate/HibernatePersonRepository.java @@ -42,7 +42,7 @@ public class HibernatePersonRepository implements PersonRepository { @Override public Person save(Person person) { - this.sessionFactory.getCurrentSession().save(person); + this.sessionFactory.getCurrentSession().persist(person); return person; } diff --git a/spring-web/spring-web.gradle b/spring-web/spring-web.gradle index 7585e176b99..80fb8fe5b5c 100644 --- a/spring-web/spring-web.gradle +++ b/spring-web/spring-web.gradle @@ -94,10 +94,10 @@ dependencies { testImplementation("org.skyscreamer:jsonassert") testImplementation("org.xmlunit:xmlunit-assertj") testImplementation("org.xmlunit:xmlunit-matchers") - testRuntimeOnly("com.sun.mail:jakarta.mail") testRuntimeOnly("com.sun.xml.bind:jaxb-core") testRuntimeOnly("com.sun.xml.bind:jaxb-impl") testRuntimeOnly("jakarta.json:jakarta.json-api") + testRuntimeOnly("org.eclipse.angus:angus-mail") testRuntimeOnly("org.eclipse:yasson") testRuntimeOnly("org.glassfish:jakarta.el") testRuntimeOnly("org.hibernate:hibernate-validator") diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java index 1f73d60f92c..10382e9d97a 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2024 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. @@ -127,7 +127,6 @@ public abstract class AbstractJsonHttpMessageConverter extends AbstractGenericHt catch (Exception ex) { throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex); } - writer.flush(); } diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/GsonHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/GsonHttpMessageConverter.java index d3306f2eb46..21b9a7ab2ec 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/GsonHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/GsonHttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -105,10 +105,12 @@ public class GsonHttpMessageConverter extends AbstractJsonHttpMessageConverter { else { getGson().toJson(object, writer); } + writer.flush(); } @Override protected boolean supportsRepeatableWrites(Object o) { return true; } + } diff --git a/spring-web/src/main/java/org/springframework/web/jsf/el/SpringBeanFacesELResolver.java b/spring-web/src/main/java/org/springframework/web/jsf/el/SpringBeanFacesELResolver.java index 81dc5b9c69b..b28883313ea 100644 --- a/spring-web/src/main/java/org/springframework/web/jsf/el/SpringBeanFacesELResolver.java +++ b/spring-web/src/main/java/org/springframework/web/jsf/el/SpringBeanFacesELResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2024 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,9 +16,6 @@ package org.springframework.web.jsf.el; -import java.beans.FeatureDescriptor; -import java.util.Iterator; - import jakarta.el.ELContext; import jakarta.el.ELException; import jakarta.el.ELResolver; @@ -129,12 +126,6 @@ public class SpringBeanFacesELResolver extends ELResolver { return false; } - @Override - @Nullable - public Iterator getFeatureDescriptors(ELContext elContext, @Nullable Object base) { - return null; - } - @Override public Class getCommonPropertyType(ELContext elContext, @Nullable Object base) { return Object.class; diff --git a/spring-web/src/main/java/org/springframework/web/jsf/el/WebApplicationContextFacesELResolver.java b/spring-web/src/main/java/org/springframework/web/jsf/el/WebApplicationContextFacesELResolver.java index a991ed8a1c4..165102f7e7f 100644 --- a/spring-web/src/main/java/org/springframework/web/jsf/el/WebApplicationContextFacesELResolver.java +++ b/spring-web/src/main/java/org/springframework/web/jsf/el/WebApplicationContextFacesELResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 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,9 +16,6 @@ package org.springframework.web.jsf.el; -import java.beans.FeatureDescriptor; -import java.util.Iterator; - import jakarta.el.ELContext; import jakarta.el.ELException; import jakarta.el.ELResolver; @@ -153,12 +150,6 @@ public class WebApplicationContextFacesELResolver extends ELResolver { return false; } - @Override - @Nullable - public Iterator getFeatureDescriptors(ELContext elContext, Object base) { - return null; - } - @Override public Class getCommonPropertyType(ELContext elContext, Object base) { return Object.class; diff --git a/spring-web/src/test/java/org/springframework/web/jsf/MockFacesContext.java b/spring-web/src/test/java/org/springframework/web/jsf/MockFacesContext.java index f7298643350..587e2b1b1ea 100644 --- a/spring-web/src/test/java/org/springframework/web/jsf/MockFacesContext.java +++ b/spring-web/src/test/java/org/springframework/web/jsf/MockFacesContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import jakarta.faces.context.ExternalContext; import jakarta.faces.context.FacesContext; import jakarta.faces.context.ResponseStream; import jakarta.faces.context.ResponseWriter; +import jakarta.faces.lifecycle.Lifecycle; import jakarta.faces.render.RenderKit; /** @@ -141,4 +142,9 @@ public class MockFacesContext extends FacesContext { public void responseComplete() { } + @Override + public Lifecycle getLifecycle() { + return null; + } + }