Jakarta EE 9 migration
Upgrades many dependency declarations; removes old EJB 2.x support and outdated Servlet-based integrations (Commons FileUpload, FreeMarker JSP support, Tiles). Closes gh-22093 Closes gh-25354 Closes gh-26185 Closes gh-27423 See gh-27424
This commit is contained in:
parent
5822f1bf85
commit
d84ca2ba90
120
build.gradle
120
build.gradle
|
@ -32,7 +32,7 @@ configure(allprojects) { project ->
|
|||
mavenBom "io.projectreactor:reactor-bom:2020.0.11"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR10"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.1"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.43.v20210629"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:11.0.6"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.30"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.2"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.2"
|
||||
|
@ -83,14 +83,10 @@ configure(allprojects) { project ->
|
|||
exclude group: "xpp3", name: "xpp3_min"
|
||||
exclude group: "xmlpull", name: "xmlpull"
|
||||
}
|
||||
dependency "org.apache.johnzon:johnzon-jsonb:1.2.10"
|
||||
dependency "org.eclipse:yasson:2.0.2"
|
||||
dependency("org.codehaus.jettison:jettison:1.3.8") {
|
||||
exclude group: "stax", name: "stax-api"
|
||||
}
|
||||
dependencySet(group: 'org.jibx', version: '1.3.3') {
|
||||
entry 'jibx-bind'
|
||||
entry 'jibx-run'
|
||||
}
|
||||
dependency "org.ogce:xpp3:1.1.6"
|
||||
dependency "org.yaml:snakeyaml:1.29"
|
||||
|
||||
|
@ -108,7 +104,6 @@ configure(allprojects) { project ->
|
|||
}
|
||||
entry 'activemq-stomp'
|
||||
}
|
||||
dependency "org.apache.bcel:bcel:6.0"
|
||||
dependency "org.apache.commons:commons-pool2:2.9.0"
|
||||
dependencySet(group: 'org.apache.derby', version: '10.14.2.0') {
|
||||
entry 'derby'
|
||||
|
@ -119,35 +114,28 @@ configure(allprojects) { project ->
|
|||
dependency "org.freemarker:freemarker:2.3.31"
|
||||
dependency "org.hsqldb:hsqldb:2.5.2"
|
||||
dependency "org.quartz-scheduler:quartz:2.3.2"
|
||||
dependency "org.codehaus.fabric3.api:commonj:1.1.0"
|
||||
dependency "net.sf.ehcache:ehcache:2.10.6"
|
||||
dependency "org.ehcache:jcache:1.0.1"
|
||||
dependency "org.ehcache:ehcache:3.4.0"
|
||||
dependency "org.hibernate:hibernate-core:5.5.7.Final"
|
||||
dependency "org.hibernate:hibernate-validator:6.2.0.Final"
|
||||
dependency "org.hibernate:hibernate-core-jakarta:5.5.7.Final"
|
||||
dependency "org.hibernate:hibernate-validator:7.0.1.Final"
|
||||
dependency "org.webjars:webjars-locator-core:0.47"
|
||||
dependency "org.webjars:underscorejs:1.8.3"
|
||||
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.52') {
|
||||
dependencySet(group: 'org.apache.tomcat', version: '10.0.11') {
|
||||
entry 'tomcat-util'
|
||||
entry('tomcat-websocket') {
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.52') {
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '10.0.11') {
|
||||
entry 'tomcat-embed-core'
|
||||
entry 'tomcat-embed-websocket'
|
||||
}
|
||||
dependencySet(group: 'io.undertow', version: '2.2.10.Final') {
|
||||
entry 'undertow-core'
|
||||
entry('undertow-websockets-jsr') {
|
||||
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
|
||||
}
|
||||
entry('undertow-servlet') {
|
||||
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_3.1_spec"
|
||||
exclude group: "org.jboss.spec.javax.annotation", name: "jboss-annotations-api_1.2_spec"
|
||||
}
|
||||
entry('undertow-servlet-jakartaee9')
|
||||
entry('undertow-websockets-jsr-jakartaee9')
|
||||
}
|
||||
|
||||
dependencySet(group: 'com.squareup.okhttp3', version: '3.14.9') {
|
||||
|
@ -162,15 +150,12 @@ configure(allprojects) { project ->
|
|||
}
|
||||
dependency 'org.apache.httpcomponents.client5:httpclient5:5.1'
|
||||
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.1.1'
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.9"
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:3.0.4"
|
||||
|
||||
dependency "org.jruby:jruby:9.2.19.0"
|
||||
dependency "org.python:jython-standalone:2.7.1"
|
||||
dependency "org.mozilla:rhino:1.7.11"
|
||||
|
||||
dependency "commons-fileupload:commons-fileupload:1.4"
|
||||
dependency "org.synchronoss.cloud:nio-multipart-parser:1.1.0"
|
||||
|
||||
dependency("org.dom4j:dom4j:2.1.3") {
|
||||
exclude group: "jaxen", name: "jaxen"
|
||||
exclude group: "net.java.dev.msv", name: "xsdlib"
|
||||
|
@ -218,69 +203,50 @@ configure(allprojects) { project ->
|
|||
dependency "org.skyscreamer:jsonassert:1.5.0"
|
||||
dependency "com.jayway.jsonpath:json-path:2.6.0"
|
||||
dependency "org.bouncycastle:bcpkix-jdk15on:1.66"
|
||||
|
||||
dependencySet(group: 'org.apache.tiles', version: '3.0.8') {
|
||||
entry 'tiles-api'
|
||||
entry('tiles-core', withoutJclOverSlf4j)
|
||||
entry('tiles-servlet', withoutJclOverSlf4j)
|
||||
entry('tiles-jsp', withoutJclOverSlf4j)
|
||||
entry('tiles-el', withoutJclOverSlf4j)
|
||||
entry('tiles-extras') {
|
||||
exclude group: "org.springframework", name: "spring-web"
|
||||
exclude group: "org.slf4j", name: "jcl-over-slf4j"
|
||||
}
|
||||
}
|
||||
dependency("org.apache.taglibs:taglibs-standard-jstlel:1.2.5") {
|
||||
exclude group: "org.apache.taglibs", name: "taglibs-standard-spec"
|
||||
}
|
||||
|
||||
dependency "com.ibm.websphere:uow:6.0.2.17"
|
||||
dependency "com.jamonapi:jamon:2.82"
|
||||
dependency "joda-time:joda-time:2.10.10"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.9"
|
||||
dependency "org.javamoney:moneta:1.3"
|
||||
|
||||
dependency "com.sun.activation:javax.activation:1.2.0"
|
||||
dependency "com.sun.mail:javax.mail:1.6.2"
|
||||
dependencySet(group: 'com.sun.xml.bind', version: '2.3.0.1') {
|
||||
dependency "javax.cache:cache-api:1.1.1"
|
||||
dependency "javax.money:money-api:1.1"
|
||||
dependency "org.javamoney:moneta:1.4.2"
|
||||
|
||||
dependency "jakarta.activation:jakarta.activation-api:2.0.1"
|
||||
dependency "jakarta.annotation:jakarta.annotation-api:2.0.0"
|
||||
dependency "jakarta.ejb:jakarta.ejb-api:4.0.0"
|
||||
dependency "jakarta.el:jakarta.el-api:4.0.0"
|
||||
dependency "jakarta.enterprise.concurrent:jakarta.enterprise.concurrent-api:2.0.0"
|
||||
dependency "jakarta.faces:jakarta.faces-api:3.0.0"
|
||||
dependency "jakarta.inject:jakarta.inject-api:2.0.0"
|
||||
dependency "jakarta.inject:jakarta.inject-tck:2.0.1"
|
||||
dependency "jakarta.interceptor:jakarta.interceptor-api:2.0.0"
|
||||
dependency "jakarta.jms:jakarta.jms-api:3.0.0"
|
||||
dependency "jakarta.json:jakarta.json-api:2.0.1"
|
||||
dependency "jakarta.json.bind:jakarta.json.bind-api:2.0.0"
|
||||
dependency "jakarta.mail:jakarta.mail-api:2.0.1"
|
||||
dependency "jakarta.persistence:jakarta.persistence-api:3.0.0"
|
||||
dependency "jakarta.resource:jakarta.resource-api:2.0.0"
|
||||
dependency "jakarta.servlet:jakarta.servlet-api:5.0.0"
|
||||
dependency "jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.0.0"
|
||||
dependency "jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:2.0.0"
|
||||
dependency "jakarta.transaction:jakarta.transaction-api:2.0.0"
|
||||
dependency "jakarta.validation:jakarta.validation-api:3.0.0"
|
||||
dependency "jakarta.websocket:jakarta.websocket-api:2.0.0"
|
||||
dependency "jakarta.xml.bind:jakarta.xml.bind-api:3.0.1"
|
||||
dependency "jakarta.xml.ws:jakarta.xml.ws-api:3.0.1"
|
||||
|
||||
dependency "com.sun.activation:jakarta.activation:2.0.1"
|
||||
dependency "com.sun.mail:jakarta.mail:2.0.1"
|
||||
dependencySet(group: 'com.sun.xml.bind', version: '3.0.2') {
|
||||
entry 'jaxb-core'
|
||||
entry 'jaxb-impl'
|
||||
entry 'jaxb-xjc'
|
||||
}
|
||||
|
||||
dependency "javax.activation:javax.activation-api:1.2.0"
|
||||
dependency "javax.annotation:javax.annotation-api:1.3.2"
|
||||
dependency "javax.cache:cache-api:1.1.0"
|
||||
dependency "javax.ejb:javax.ejb-api:3.2"
|
||||
dependency "javax.el:javax.el-api:3.0.1-b04"
|
||||
dependency "javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0"
|
||||
dependency "javax.faces:javax.faces-api:2.2"
|
||||
dependency "javax.inject:javax.inject:1"
|
||||
dependency "javax.inject:javax.inject-tck:1"
|
||||
dependency "javax.interceptor:javax.interceptor-api:1.2.2"
|
||||
dependency "javax.jms:javax.jms-api:2.0.1"
|
||||
dependency "javax.json:javax.json-api:1.1.4"
|
||||
dependency "javax.json.bind:javax.json.bind-api:1.0"
|
||||
dependency "javax.mail:javax.mail-api:1.6.2"
|
||||
dependency "javax.money:money-api:1.0.3"
|
||||
dependency "javax.resource:javax.resource-api:1.7.1"
|
||||
dependency "javax.servlet:javax.servlet-api:4.0.1"
|
||||
dependency "javax.servlet.jsp:javax.servlet.jsp-api:2.3.2-b02"
|
||||
dependency "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1"
|
||||
dependency "javax.transaction:javax.transaction-api:1.3"
|
||||
dependency "javax.validation:validation-api:2.0.1.Final"
|
||||
dependency "javax.websocket:javax.websocket-api:1.1"
|
||||
dependency "javax.xml.bind:jaxb-api:2.3.1"
|
||||
dependency "javax.xml.ws:jaxws-api:2.3.1"
|
||||
|
||||
dependency "org.eclipse.persistence:javax.persistence:2.2.0"
|
||||
|
||||
// Substitute for "javax.management:jmxremote_optional:1.0.1_04" which
|
||||
// is not available on Maven Central
|
||||
dependency "org.glassfish.external:opendmk_jmxremote_optional_jar:1.0-b01-ea"
|
||||
dependency "org.glassfish:javax.el:3.0.1-b08"
|
||||
dependency "org.glassfish.main:javax.jws:4.0-b33"
|
||||
dependency "org.glassfish.tyrus:tyrus-container-servlet:1.13.1"
|
||||
dependency "org.glassfish:jakarta.el:4.0.2"
|
||||
dependency "org.glassfish.tyrus:tyrus-container-servlet:2.0.1"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:3.0.2"
|
||||
}
|
||||
generatedPomCustomization {
|
||||
enabled = false
|
||||
|
|
|
@ -15,12 +15,12 @@ dependencies {
|
|||
testImplementation(project(":spring-test"))
|
||||
testImplementation(project(":spring-tx"))
|
||||
testImplementation(project(":spring-web"))
|
||||
testImplementation("javax.inject:javax.inject")
|
||||
testImplementation("javax.resource:javax.resource-api")
|
||||
testImplementation("javax.servlet:javax.servlet-api")
|
||||
testImplementation("jakarta.inject:jakarta.inject-api")
|
||||
testImplementation("jakarta.resource:jakarta.resource-api")
|
||||
testImplementation("jakarta.servlet:jakarta.servlet-api")
|
||||
testImplementation("org.aspectj:aspectjweaver")
|
||||
testImplementation("org.hsqldb:hsqldb")
|
||||
testImplementation("org.hibernate:hibernate-core")
|
||||
testImplementation("org.hibernate:hibernate-core-jakarta")
|
||||
}
|
||||
|
||||
normalization {
|
||||
|
|
|
@ -20,8 +20,7 @@ import java.io.IOException;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
|
|
|
@ -21,9 +21,8 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -314,16 +313,16 @@ class ClassPathBeanDefinitionScannerJsr330ScopeIntegrationTests {
|
|||
if (definition instanceof AnnotatedBeanDefinition) {
|
||||
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
|
||||
for (String type : annDef.getMetadata().getAnnotationTypes()) {
|
||||
if (type.equals(javax.inject.Singleton.class.getName())) {
|
||||
if (type.equals(jakarta.inject.Singleton.class.getName())) {
|
||||
metadata.setScopeName(BeanDefinition.SCOPE_SINGLETON);
|
||||
break;
|
||||
}
|
||||
else if (annDef.getMetadata().getMetaAnnotationTypes(type).contains(javax.inject.Scope.class.getName())) {
|
||||
else if (annDef.getMetadata().getMetaAnnotationTypes(type).contains(jakarta.inject.Scope.class.getName())) {
|
||||
metadata.setScopeName(type.substring(type.length() - 13, type.length() - 6).toLowerCase());
|
||||
metadata.setScopedProxyMode(scopedProxyMode);
|
||||
break;
|
||||
}
|
||||
else if (type.startsWith("javax.inject")) {
|
||||
else if (type.startsWith("jakarta.inject")) {
|
||||
metadata.setScopeName(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
}
|
||||
}
|
||||
|
@ -391,14 +390,14 @@ class ClassPathBeanDefinitionScannerJsr330ScopeIntegrationTests {
|
|||
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@javax.inject.Scope
|
||||
@jakarta.inject.Scope
|
||||
public @interface RequestScoped {
|
||||
}
|
||||
|
||||
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@javax.inject.Scope
|
||||
@jakarta.inject.Scope
|
||||
public @interface SessionScoped {
|
||||
}
|
||||
|
||||
|
|
|
@ -41,9 +41,6 @@ import org.springframework.context.support.GenericApplicationContext;
|
|||
import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.jca.context.ResourceAdapterApplicationContext;
|
||||
import org.springframework.jca.support.SimpleBootstrapContext;
|
||||
import org.springframework.jca.work.SimpleTaskWorkManager;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
import org.springframework.mock.web.MockServletConfig;
|
||||
|
@ -535,22 +532,6 @@ public class EnvironmentSystemIntegrationTests {
|
|||
assertThat(environment.getProperty("pSysProps1")).isEqualTo("pSysProps1Value");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resourceAdapterApplicationContext() {
|
||||
ResourceAdapterApplicationContext ctx = new ResourceAdapterApplicationContext(new SimpleBootstrapContext(new SimpleTaskWorkManager()));
|
||||
|
||||
assertHasStandardEnvironment(ctx);
|
||||
|
||||
registerEnvironmentBeanDefinition(ctx);
|
||||
|
||||
ctx.setEnvironment(prodEnv);
|
||||
ctx.refresh();
|
||||
|
||||
assertHasEnvironment(ctx, prodEnv);
|
||||
assertEnvironmentBeanRegistered(ctx);
|
||||
assertEnvironmentAwareInvoked(ctx, prodEnv);
|
||||
}
|
||||
|
||||
@Test
|
||||
void abstractApplicationContextValidatesRequiredPropertiesOnRefresh() {
|
||||
{
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
<props>
|
||||
<prop key="setA*">PROPAGATION_REQUIRED</prop>
|
||||
<prop key="rollbackOnly">PROPAGATION_REQUIRED</prop>
|
||||
<prop key="echoException">PROPAGATION_REQUIRED,+javax.servlet.ServletException,-java.lang.Exception</prop>
|
||||
<prop key="echoException">PROPAGATION_REQUIRED,+jakarta.servlet.ServletException,-java.lang.Exception</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -47,7 +47,7 @@ import org.springframework.util.ClassUtils;
|
|||
* target method needs to implement the same signature, it will have to return
|
||||
* a temporary Future handle that just passes the return value through
|
||||
* (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult}
|
||||
* or EJB 3.1's {@code javax.ejb.AsyncResult}).
|
||||
* or EJB's {@code jakarta.ejb.AsyncResult}).
|
||||
*
|
||||
* <p>When the return type is {@code java.util.concurrent.Future}, any exception thrown
|
||||
* during the execution can be accessed and managed by the caller. With {@code void}
|
||||
|
|
|
@ -29,14 +29,14 @@ dependencies {
|
|||
optional(project(":spring-orm")) // for JPA exception translation support
|
||||
optional(project(":spring-tx")) // for JPA, @Transactional support
|
||||
optional("javax.cache:cache-api") // for JCache aspect
|
||||
optional("javax.transaction:javax.transaction-api") // for @javax.transaction.Transactional support
|
||||
optional("jakarta.transaction:jakarta.transaction-api") // for @javax.transaction.Transactional support
|
||||
testImplementation(project(":spring-core")) // for CodeStyleAspect
|
||||
testImplementation(project(":spring-test"))
|
||||
testImplementation(testFixtures(project(":spring-context")))
|
||||
testImplementation(testFixtures(project(":spring-context-support")))
|
||||
testImplementation(testFixtures(project(":spring-core")))
|
||||
testImplementation(testFixtures(project(":spring-tx")))
|
||||
testImplementation("javax.mail:javax.mail-api")
|
||||
testImplementation("jakarta.mail:jakarta.mail-api")
|
||||
testCompileOnly("org.aspectj:aspectjrt")
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.springframework.transaction.config.TransactionManagementConfigUtils;
|
|||
/**
|
||||
* {@code @Configuration} class that registers the Spring infrastructure beans necessary
|
||||
* to enable AspectJ-based annotation-driven transaction management for the JTA 1.2
|
||||
* {@link javax.transaction.Transactional} annotation in addition to Spring's own
|
||||
* {@link jakarta.transaction.Transactional} annotation in addition to Spring's own
|
||||
* {@link org.springframework.transaction.annotation.Transactional} annotation.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import org.aspectj.lang.annotation.RequiredTypes;
|
||||
|
||||
|
@ -24,7 +24,7 @@ import org.springframework.transaction.annotation.AnnotationTransactionAttribute
|
|||
|
||||
/**
|
||||
* Concrete AspectJ transaction aspect using the JTA 1.2
|
||||
* {@link javax.transaction.Transactional} annotation.
|
||||
* {@link jakarta.transaction.Transactional} annotation.
|
||||
*
|
||||
* <p>When using this aspect, you <i>must</i> annotate the implementation class
|
||||
* (and/or methods within that class), <i>not</i> the interface (if any) that
|
||||
|
@ -42,10 +42,10 @@ import org.springframework.transaction.annotation.AnnotationTransactionAttribute
|
|||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.2
|
||||
* @see javax.transaction.Transactional
|
||||
* @see jakarta.transaction.Transactional
|
||||
* @see AnnotationTransactionAspect
|
||||
*/
|
||||
@RequiredTypes("javax.transaction.Transactional")
|
||||
@RequiredTypes("jakarta.transaction.Transactional")
|
||||
public aspect JtaAnnotationTransactionAspect extends AbstractTransactionAspect {
|
||||
|
||||
public JtaAnnotationTransactionAspect() {
|
||||
|
|
|
@ -18,8 +18,7 @@ package org.springframework.transaction.aspectj;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@ apply plugin: "kotlin"
|
|||
|
||||
dependencies {
|
||||
api(project(":spring-core"))
|
||||
optional("javax.inject:javax.inject")
|
||||
optional("jakarta.inject:jakarta.inject-api")
|
||||
optional("org.yaml:snakeyaml")
|
||||
optional("org.codehaus.groovy:groovy-xml")
|
||||
optional("org.jetbrains.kotlin:kotlin-reflect")
|
||||
optional("org.jetbrains.kotlin:kotlin-stdlib")
|
||||
testImplementation(testFixtures(project(":spring-core")))
|
||||
testImplementation("javax.annotation:javax.annotation-api")
|
||||
testImplementation("jakarta.annotation:jakarta.annotation-api")
|
||||
testFixturesApi("org.junit.jupiter:junit-jupiter-api")
|
||||
testFixturesImplementation("org.assertj:assertj-core")
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import java.lang.annotation.Target;
|
|||
/**
|
||||
* Marks a constructor, field, setter method, or config method as to be autowired by
|
||||
* Spring's dependency injection facilities. This is an alternative to the JSR-330
|
||||
* {@link javax.inject.Inject} annotation, adding required-vs-optional semantics.
|
||||
* {@link jakarta.inject.Inject} annotation, adding required-vs-optional semantics.
|
||||
*
|
||||
* <h3>Autowired Constructors</h3>
|
||||
* <p>Only one constructor of any given bean class may declare this annotation with the
|
||||
|
|
|
@ -75,7 +75,7 @@ import org.springframework.util.StringUtils;
|
|||
* by default, Spring's {@link Autowired @Autowired} and {@link Value @Value}
|
||||
* annotations.
|
||||
*
|
||||
* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
|
||||
* <p>Also supports JSR-330's {@link jakarta.inject.Inject @Inject} annotation,
|
||||
* if available, as a direct alternative to Spring's own {@code @Autowired}.
|
||||
*
|
||||
* <h3>Autowired Constructors</h3>
|
||||
|
@ -154,7 +154,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
/**
|
||||
* Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
|
||||
* standard {@link Autowired @Autowired} and {@link Value @Value} annotations.
|
||||
* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
|
||||
* <p>Also supports JSR-330's {@link jakarta.inject.Inject @Inject} annotation,
|
||||
* if available.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -163,8 +163,8 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
this.autowiredAnnotationTypes.add(Value.class);
|
||||
try {
|
||||
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
|
||||
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
|
||||
ClassUtils.forName("jakarta.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
|
||||
logger.trace("JSR-330 'jakarta.inject.Inject' annotation found and supported for autowiring");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - simply skip.
|
||||
|
@ -177,7 +177,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
* setter methods, and arbitrary config methods.
|
||||
* <p>The default autowired annotation types are the Spring-provided
|
||||
* {@link Autowired @Autowired} and {@link Value @Value} annotations as well
|
||||
* as JSR-330's {@link javax.inject.Inject @Inject} annotation, if available.
|
||||
* as JSR-330's {@link jakarta.inject.Inject @Inject} annotation, if available.
|
||||
* <p>This setter property exists so that developers can provide their own
|
||||
* (non-Spring-specific) annotation type to indicate that a member is supposed
|
||||
* to be autowired.
|
||||
|
@ -193,7 +193,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
* setter methods, and arbitrary config methods.
|
||||
* <p>The default autowired annotation types are the Spring-provided
|
||||
* {@link Autowired @Autowired} and {@link Value @Value} annotations as well
|
||||
* as JSR-330's {@link javax.inject.Inject @Inject} annotation, if available.
|
||||
* as JSR-330's {@link jakarta.inject.Inject @Inject} annotation, if available.
|
||||
* <p>This setter property exists so that developers can provide their own
|
||||
* (non-Spring-specific) annotation types to indicate that a member is supposed
|
||||
* to be autowired.
|
||||
|
@ -537,9 +537,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
* @param ann the Autowired annotation
|
||||
* @return whether the annotation indicates that a dependency is required
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "cast"})
|
||||
protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {
|
||||
// The following (AnnotationAttributes) cast is required on JDK 9+.
|
||||
return determineRequiredStatus((AnnotationAttributes)
|
||||
ann.asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation.getType())));
|
||||
}
|
||||
|
|
|
@ -66,9 +66,9 @@ import org.springframework.util.ReflectionUtils;
|
|||
* init method and destroy method, respectively.
|
||||
*
|
||||
* <p>Spring's {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor}
|
||||
* supports the JSR-250 {@link javax.annotation.PostConstruct} and {@link javax.annotation.PreDestroy}
|
||||
* supports the JSR-250 {@link jakarta.annotation.PostConstruct} and {@link jakarta.annotation.PreDestroy}
|
||||
* annotations out of the box, as init annotation and destroy annotation, respectively.
|
||||
* Furthermore, it also supports the {@link javax.annotation.Resource} annotation
|
||||
* Furthermore, it also supports the {@link jakarta.annotation.Resource} annotation
|
||||
* for annotation-driven injection of named beans.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
|
@ -117,7 +117,7 @@ public class InitDestroyAnnotationBeanPostProcessor
|
|||
* methods to call after configuration of a bean.
|
||||
* <p>Any custom annotation can be used, since there are no required
|
||||
* annotation attributes. There is no default, although a typical choice
|
||||
* is the JSR-250 {@link javax.annotation.PostConstruct} annotation.
|
||||
* is the JSR-250 {@link jakarta.annotation.PostConstruct} annotation.
|
||||
*/
|
||||
public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
|
||||
this.initAnnotationType = initAnnotationType;
|
||||
|
@ -128,7 +128,7 @@ public class InitDestroyAnnotationBeanPostProcessor
|
|||
* methods to call when the context is shutting down.
|
||||
* <p>Any custom annotation can be used, since there are no required
|
||||
* annotation attributes. There is no default, although a typical choice
|
||||
* is the JSR-250 {@link javax.annotation.PreDestroy} annotation.
|
||||
* is the JSR-250 {@link jakarta.annotation.PreDestroy} annotation.
|
||||
*/
|
||||
public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
|
||||
this.destroyAnnotationType = destroyAnnotationType;
|
||||
|
|
|
@ -46,7 +46,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.
|
||||
*
|
||||
* <p>Also supports JSR-330's {@link javax.inject.Qualifier} annotation, if available.
|
||||
* <p>Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation, if available.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
|
@ -66,13 +66,13 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
|||
/**
|
||||
* Create a new QualifierAnnotationAutowireCandidateResolver
|
||||
* for Spring's standard {@link Qualifier} annotation.
|
||||
* <p>Also supports JSR-330's {@link javax.inject.Qualifier} annotation, if available.
|
||||
* <p>Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation, if available.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public QualifierAnnotationAutowireCandidateResolver() {
|
||||
this.qualifierTypes.add(Qualifier.class);
|
||||
try {
|
||||
this.qualifierTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Qualifier",
|
||||
this.qualifierTypes.add((Class<? extends Annotation>) ClassUtils.forName("jakarta.inject.Qualifier",
|
||||
QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
|
|
|
@ -182,7 +182,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
|||
|
||||
/**
|
||||
* Check whether the underlying field is annotated with any variant of a
|
||||
* {@code Nullable} annotation, e.g. {@code javax.annotation.Nullable} or
|
||||
* {@code Nullable} annotation, e.g. {@code jakarta.annotation.Nullable} or
|
||||
* {@code edu.umd.cs.findbugs.annotations.Nullable}.
|
||||
*/
|
||||
private boolean hasNullableAnnotation() {
|
||||
|
|
|
@ -18,7 +18,7 @@ package org.springframework.beans.factory.config;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.inject.Provider;
|
||||
import jakarta.inject.Provider;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
|
@ -27,18 +27,18 @@ import org.springframework.util.Assert;
|
|||
|
||||
/**
|
||||
* A {@link org.springframework.beans.factory.FactoryBean} implementation that
|
||||
* returns a value which is a JSR-330 {@link javax.inject.Provider} that in turn
|
||||
* returns a value which is a JSR-330 {@link jakarta.inject.Provider} that in turn
|
||||
* returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}.
|
||||
*
|
||||
* <p>This is basically a JSR-330 compliant variant of Spring's good old
|
||||
* {@link ObjectFactoryCreatingFactoryBean}. It can be used for traditional
|
||||
* external dependency injection configuration that targets a property or
|
||||
* constructor argument of type {@code javax.inject.Provider}, as an
|
||||
* constructor argument of type {@code jakarta.inject.Provider}, as an
|
||||
* alternative to JSR-330's {@code @Inject} annotation-driven approach.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0.2
|
||||
* @see javax.inject.Provider
|
||||
* @see jakarta.inject.Provider
|
||||
* @see ObjectFactoryCreatingFactoryBean
|
||||
*/
|
||||
public class ProviderCreatingFactoryBean extends AbstractFactoryBean<Provider<Object>> {
|
||||
|
|
|
@ -138,7 +138,7 @@ public interface Scope {
|
|||
* <p>The exact meaning of the conversation ID depends on the underlying
|
||||
* storage mechanism. In the case of session-scoped objects, the
|
||||
* conversation ID would typically be equal to (or derived from) the
|
||||
* {@link javax.servlet.http.HttpSession#getId() session ID}; in the
|
||||
* {@link jakarta.servlet.http.HttpSession#getId() session ID}; in the
|
||||
* case of a custom conversation that sits within the overall session,
|
||||
* the specific ID for the current conversation would be appropriate.
|
||||
* <p><b>Note: This is an optional operation.</b> It is perfectly valid to
|
||||
|
|
|
@ -41,7 +41,7 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.inject.Provider;
|
||||
import jakarta.inject.Provider;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
|
@ -125,7 +125,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
static {
|
||||
try {
|
||||
javaxInjectProviderClass =
|
||||
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
|
||||
ClassUtils.forName("jakarta.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - Provider interface simply not supported then.
|
||||
|
@ -1651,7 +1651,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
|
||||
/**
|
||||
* Determine the candidate with the highest priority in the given set of beans.
|
||||
* <p>Based on {@code @javax.annotation.Priority}. As defined by the related
|
||||
* <p>Based on {@code @jakarta.annotation.Priority}. As defined by the related
|
||||
* {@link org.springframework.core.Ordered} interface, the lowest value has
|
||||
* the highest priority.
|
||||
* @param candidates a Map of candidate names and candidate instances
|
||||
|
@ -1711,7 +1711,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
|
||||
/**
|
||||
* Return the priority assigned for the given bean instance by
|
||||
* the {@code javax.annotation.Priority} annotation.
|
||||
* the {@code jakarta.annotation.Priority} annotation.
|
||||
* <p>The default implementation delegates to the specified
|
||||
* {@link #setDependencyComparator dependency comparator}, checking its
|
||||
* {@link OrderComparator#getPriority method} if it is an extension of
|
||||
|
@ -2086,8 +2086,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
|
||||
|
||||
/**
|
||||
* Separate inner class for avoiding a hard dependency on the {@code javax.inject} API.
|
||||
* Actual {@code javax.inject.Provider} implementation is nested here in order to make it
|
||||
* Separate inner class for avoiding a hard dependency on the {@code jakarta.inject} API.
|
||||
* Actual {@code jakarta.inject.Provider} implementation is nested here in order to make it
|
||||
* invisible for Graal's introspection of DefaultListableBeanFactory's nested classes.
|
||||
*/
|
||||
private class Jsr330Factory implements Serializable {
|
||||
|
|
|
@ -36,8 +36,7 @@ import java.util.concurrent.Callable;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
|
||||
import jakarta.annotation.Priority;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
|
|
|
@ -23,10 +23,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Provider;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -51,7 +50,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|||
|
||||
/**
|
||||
* Unit tests for {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor}
|
||||
* processing the JSR-330 {@link javax.inject.Inject} annotation.
|
||||
* processing the JSR-330 {@link jakarta.inject.Inject} annotation.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
|
|
|
@ -18,8 +18,7 @@ package org.springframework.beans.factory.config;
|
|||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
import jakarta.inject.Provider;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
|
@ -2,8 +2,8 @@ description = "Spring Context Indexer"
|
|||
|
||||
dependencies {
|
||||
testImplementation(project(":spring-context"))
|
||||
testImplementation("javax.inject:javax.inject")
|
||||
testImplementation("javax.annotation:javax.annotation-api")
|
||||
testImplementation("javax.transaction:javax.transaction-api")
|
||||
testImplementation("org.eclipse.persistence:javax.persistence")
|
||||
testImplementation("jakarta.inject:jakarta.inject-api")
|
||||
testImplementation("jakarta.annotation:jakarta.annotation-api")
|
||||
testImplementation("jakarta.persistence:jakarta.persistence-api")
|
||||
testImplementation("jakarta.transaction:jakarta.transaction-api")
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ class StandardStereotypesProvider implements StereotypesProvider {
|
|||
}
|
||||
for (AnnotationMirror annotation : this.typeHelper.getAllAnnotationMirrors(element)) {
|
||||
String type = this.typeHelper.getType(annotation);
|
||||
if (type.startsWith("javax.")) {
|
||||
if (type.startsWith("jakarta.")) {
|
||||
stereotypes.add(type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,14 +21,13 @@ import java.io.FileInputStream;
|
|||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javax.annotation.ManagedBean;
|
||||
import javax.inject.Named;
|
||||
import javax.persistence.Converter;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import jakarta.annotation.ManagedBean;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.persistence.Converter;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.context.index.sample.cdi;
|
||||
|
||||
import javax.annotation.ManagedBean;
|
||||
import jakarta.annotation.ManagedBean;
|
||||
|
||||
/**
|
||||
* Test candidate for a CDI {@link ManagedBean}.
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.context.index.sample.cdi;
|
||||
|
||||
import javax.inject.Named;
|
||||
import jakarta.inject.Named;
|
||||
|
||||
/**
|
||||
* Test candidate for a CDI {@link Named} bean.
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.context.index.sample.cdi;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
/**
|
||||
* Test candidate for {@link Transactional}. This verifies that the annotation processor
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.context.index.sample.jpa;
|
||||
|
||||
import javax.persistence.Converter;
|
||||
import jakarta.persistence.Converter;
|
||||
|
||||
/**
|
||||
* Test candidate for {@link Converter}.
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.context.index.sample.jpa;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* Test candidate for {@link Embeddable}.
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.context.index.sample.jpa;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
/**
|
||||
* Test candidate for {@link Entity}.
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.context.index.sample.jpa;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* Test candidate for {@link MappedSuperclass}.
|
||||
|
|
|
@ -6,13 +6,11 @@ dependencies {
|
|||
api(project(":spring-core"))
|
||||
optional(project(":spring-jdbc")) // for Quartz support
|
||||
optional(project(":spring-tx")) // for Quartz support
|
||||
optional("javax.activation:javax.activation-api")
|
||||
optional("javax.mail:javax.mail-api")
|
||||
optional("jakarta.activation:jakarta.activation-api")
|
||||
optional("jakarta.mail:jakarta.mail-api")
|
||||
optional("javax.cache:cache-api")
|
||||
optional("com.github.ben-manes.caffeine:caffeine")
|
||||
optional("net.sf.ehcache:ehcache")
|
||||
optional("org.quartz-scheduler:quartz")
|
||||
optional("org.codehaus.fabric3.api:commonj")
|
||||
optional("org.freemarker:freemarker")
|
||||
testImplementation(project(":spring-context"))
|
||||
testImplementation(testFixtures(project(":spring-beans")))
|
||||
|
@ -20,12 +18,11 @@ dependencies {
|
|||
testImplementation(testFixtures(project(":spring-core")))
|
||||
testImplementation(testFixtures(project(":spring-tx")))
|
||||
testImplementation("org.hsqldb:hsqldb")
|
||||
testImplementation("org.hibernate:hibernate-validator")
|
||||
testImplementation("javax.annotation:javax.annotation-api")
|
||||
testImplementation("jakarta.annotation:jakarta.annotation-api")
|
||||
testRuntimeOnly("org.ehcache:jcache")
|
||||
testRuntimeOnly("org.ehcache:ehcache")
|
||||
testRuntimeOnly("org.glassfish:javax.el")
|
||||
testRuntimeOnly("com.sun.mail:javax.mail")
|
||||
testRuntimeOnly("org.glassfish:jakarta.el")
|
||||
testRuntimeOnly("com.sun.mail:jakarta.mail")
|
||||
testFixturesApi("org.junit.jupiter:junit-jupiter-api")
|
||||
testFixturesImplementation("org.assertj:assertj-core")
|
||||
testFixturesImplementation("org.mockito:mockito-core")
|
||||
|
|
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.cache.ehcache;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
import net.sf.ehcache.Status;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.SimpleValueWrapper;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Cache} implementation on top of an {@link Ehcache} instance.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.1
|
||||
* @see EhCacheCacheManager
|
||||
*/
|
||||
public class EhCacheCache implements Cache {
|
||||
|
||||
private final Ehcache cache;
|
||||
|
||||
|
||||
/**
|
||||
* Create an {@link EhCacheCache} instance.
|
||||
* @param ehcache the backing Ehcache instance
|
||||
*/
|
||||
public EhCacheCache(Ehcache ehcache) {
|
||||
Assert.notNull(ehcache, "Ehcache must not be null");
|
||||
Status status = ehcache.getStatus();
|
||||
if (!Status.STATUS_ALIVE.equals(status)) {
|
||||
throw new IllegalArgumentException(
|
||||
"An 'alive' Ehcache is required - current cache is " + status.toString());
|
||||
}
|
||||
this.cache = ehcache;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final String getName() {
|
||||
return this.cache.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Ehcache getNativeCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ValueWrapper get(Object key) {
|
||||
Element element = lookup(key);
|
||||
return toValueWrapper(element);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T get(Object key, @Nullable Class<T> type) {
|
||||
Element element = this.cache.get(key);
|
||||
Object value = (element != null ? element.getObjectValue() : null);
|
||||
if (value != null && type != null && !type.isInstance(value)) {
|
||||
throw new IllegalStateException(
|
||||
"Cached value is not of required type [" + type.getName() + "]: " + value);
|
||||
}
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T get(Object key, Callable<T> valueLoader) {
|
||||
Element element = lookup(key);
|
||||
if (element != null) {
|
||||
return (T) element.getObjectValue();
|
||||
}
|
||||
else {
|
||||
this.cache.acquireWriteLockOnKey(key);
|
||||
try {
|
||||
element = lookup(key); // one more attempt with the write lock
|
||||
if (element != null) {
|
||||
return (T) element.getObjectValue();
|
||||
}
|
||||
else {
|
||||
return loadValue(key, valueLoader);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.cache.releaseWriteLockOnKey(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T loadValue(Object key, Callable<T> valueLoader) {
|
||||
T value;
|
||||
try {
|
||||
value = valueLoader.call();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new ValueRetrievalException(key, valueLoader, ex);
|
||||
}
|
||||
put(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Object key, @Nullable Object value) {
|
||||
this.cache.put(new Element(key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
|
||||
Element existingElement = this.cache.putIfAbsent(new Element(key, value));
|
||||
return toValueWrapper(existingElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) {
|
||||
this.cache.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evictIfPresent(Object key) {
|
||||
return this.cache.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.cache.removeAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean invalidate() {
|
||||
boolean notEmpty = (this.cache.getSize() > 0);
|
||||
this.cache.removeAll();
|
||||
return notEmpty;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private Element lookup(Object key) {
|
||||
return this.cache.get(key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ValueWrapper toValueWrapper(@Nullable Element element) {
|
||||
return (element != null ? new SimpleValueWrapper(element.getObjectValue()) : null);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.cache.ehcache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Status;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* CacheManager backed by an EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.1
|
||||
* @see EhCacheCache
|
||||
*/
|
||||
public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManager {
|
||||
|
||||
@Nullable
|
||||
private net.sf.ehcache.CacheManager cacheManager;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new EhCacheCacheManager, setting the target EhCache CacheManager
|
||||
* through the {@link #setCacheManager} bean property.
|
||||
*/
|
||||
public EhCacheCacheManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new EhCacheCacheManager for the given backing EhCache CacheManager.
|
||||
* @param cacheManager the backing EhCache {@link net.sf.ehcache.CacheManager}
|
||||
*/
|
||||
public EhCacheCacheManager(net.sf.ehcache.CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the backing EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*/
|
||||
public void setCacheManager(@Nullable net.sf.ehcache.CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the backing EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*/
|
||||
@Nullable
|
||||
public net.sf.ehcache.CacheManager getCacheManager() {
|
||||
return this.cacheManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (getCacheManager() == null) {
|
||||
setCacheManager(EhCacheManagerUtils.buildCacheManager());
|
||||
}
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
net.sf.ehcache.CacheManager cacheManager = getCacheManager();
|
||||
Assert.state(cacheManager != null, "No CacheManager set");
|
||||
|
||||
Status status = cacheManager.getStatus();
|
||||
if (!Status.STATUS_ALIVE.equals(status)) {
|
||||
throw new IllegalStateException(
|
||||
"An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
|
||||
}
|
||||
|
||||
String[] names = getCacheManager().getCacheNames();
|
||||
Collection<Cache> caches = new LinkedHashSet<>(names.length);
|
||||
for (String name : names) {
|
||||
caches.add(new EhCacheCache(getCacheManager().getEhcache(name)));
|
||||
}
|
||||
return caches;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cache getMissingCache(String name) {
|
||||
net.sf.ehcache.CacheManager cacheManager = getCacheManager();
|
||||
Assert.state(cacheManager != null, "No CacheManager set");
|
||||
|
||||
// Check the EhCache cache again (in case the cache was added at runtime)
|
||||
Ehcache ehcache = cacheManager.getEhcache(name);
|
||||
if (ehcache != null) {
|
||||
return new EhCacheCache(ehcache);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,329 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.cache.ehcache;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
|
||||
import net.sf.ehcache.config.CacheConfiguration;
|
||||
import net.sf.ehcache.constructs.blocking.BlockingCache;
|
||||
import net.sf.ehcache.constructs.blocking.CacheEntryFactory;
|
||||
import net.sf.ehcache.constructs.blocking.SelfPopulatingCache;
|
||||
import net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory;
|
||||
import net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache;
|
||||
import net.sf.ehcache.event.CacheEventListener;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} that creates a named EhCache {@link net.sf.ehcache.Cache} instance
|
||||
* (or a decorator that implements the {@link net.sf.ehcache.Ehcache} interface),
|
||||
* representing a cache region within an EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
*
|
||||
* <p>If the specified named cache is not configured in the cache configuration descriptor,
|
||||
* this FactoryBean will construct an instance of a Cache with the provided name and the
|
||||
* specified cache properties and add it to the CacheManager for later retrieval. If some
|
||||
* or all properties are not set at configuration time, this FactoryBean will use defaults.
|
||||
*
|
||||
* <p>Note: If the named Cache instance is found, the properties will be ignored and the
|
||||
* Cache instance will be retrieved from the CacheManager.
|
||||
*
|
||||
* <p>Note: As of Spring 5.0, Spring's EhCache support requires EhCache 2.10 or higher.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Dmitriy Kopylenko
|
||||
* @since 1.1.1
|
||||
* @see #setCacheManager
|
||||
* @see EhCacheManagerFactoryBean
|
||||
* @see net.sf.ehcache.Cache
|
||||
*/
|
||||
public class EhCacheFactoryBean extends CacheConfiguration implements FactoryBean<Ehcache>, BeanNameAware, InitializingBean {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@Nullable
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private boolean blocking = false;
|
||||
|
||||
@Nullable
|
||||
private CacheEntryFactory cacheEntryFactory;
|
||||
|
||||
@Nullable
|
||||
private BootstrapCacheLoader bootstrapCacheLoader;
|
||||
|
||||
@Nullable
|
||||
private Set<CacheEventListener> cacheEventListeners;
|
||||
|
||||
private boolean disabled = false;
|
||||
|
||||
@Nullable
|
||||
private String beanName;
|
||||
|
||||
@Nullable
|
||||
private Ehcache cache;
|
||||
|
||||
|
||||
public EhCacheFactoryBean() {
|
||||
setMaxEntriesLocalHeap(10000);
|
||||
setMaxEntriesLocalDisk(10000000);
|
||||
setTimeToLiveSeconds(120);
|
||||
setTimeToIdleSeconds(120);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a CacheManager from which to retrieve a named Cache instance.
|
||||
* By default, {@code CacheManager.getInstance()} will be called.
|
||||
* <p>Note that in particular for persistent caches, it is advisable to
|
||||
* properly handle the shutdown of the CacheManager: Set up a separate
|
||||
* EhCacheManagerFactoryBean and pass a reference to this bean property.
|
||||
* <p>A separate EhCacheManagerFactoryBean is also necessary for loading
|
||||
* EhCache configuration from a non-default config location.
|
||||
* @see EhCacheManagerFactoryBean
|
||||
* @see net.sf.ehcache.CacheManager#getInstance
|
||||
*/
|
||||
public void setCacheManager(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a name for which to retrieve or create a cache instance.
|
||||
* Default is the bean name of this EhCacheFactoryBean.
|
||||
*/
|
||||
public void setCacheName(String cacheName) {
|
||||
setName(cacheName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time to live.
|
||||
* @see #setTimeToLiveSeconds(long)
|
||||
*/
|
||||
public void setTimeToLive(int timeToLive) {
|
||||
setTimeToLiveSeconds(timeToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time to idle.
|
||||
* @see #setTimeToIdleSeconds(long)
|
||||
*/
|
||||
public void setTimeToIdle(int timeToIdle) {
|
||||
setTimeToIdleSeconds(timeToIdle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the disk spool buffer size (in MB).
|
||||
* @see #setDiskSpoolBufferSizeMB(int)
|
||||
*/
|
||||
public void setDiskSpoolBufferSize(int diskSpoolBufferSize) {
|
||||
setDiskSpoolBufferSizeMB(diskSpoolBufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use a blocking cache that lets read attempts block
|
||||
* until the requested element is created.
|
||||
* <p>If you intend to build a self-populating blocking cache,
|
||||
* consider specifying a {@link #setCacheEntryFactory CacheEntryFactory}.
|
||||
* @see net.sf.ehcache.constructs.blocking.BlockingCache
|
||||
* @see #setCacheEntryFactory
|
||||
*/
|
||||
public void setBlocking(boolean blocking) {
|
||||
this.blocking = blocking;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an EhCache {@link net.sf.ehcache.constructs.blocking.CacheEntryFactory}
|
||||
* to use for a self-populating cache. If such a factory is specified,
|
||||
* the cache will be decorated with EhCache's
|
||||
* {@link net.sf.ehcache.constructs.blocking.SelfPopulatingCache}.
|
||||
* <p>The specified factory can be of type
|
||||
* {@link net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory},
|
||||
* which will lead to the use of an
|
||||
* {@link net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache}.
|
||||
* <p>Note: Any such self-populating cache is automatically a blocking cache.
|
||||
* @see net.sf.ehcache.constructs.blocking.SelfPopulatingCache
|
||||
* @see net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache
|
||||
* @see net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory
|
||||
*/
|
||||
public void setCacheEntryFactory(CacheEntryFactory cacheEntryFactory) {
|
||||
this.cacheEntryFactory = cacheEntryFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an EhCache {@link net.sf.ehcache.bootstrap.BootstrapCacheLoader}
|
||||
* for this cache, if any.
|
||||
*/
|
||||
public void setBootstrapCacheLoader(BootstrapCacheLoader bootstrapCacheLoader) {
|
||||
this.bootstrapCacheLoader = bootstrapCacheLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify EhCache {@link net.sf.ehcache.event.CacheEventListener cache event listeners}
|
||||
* to registered with this cache.
|
||||
*/
|
||||
public void setCacheEventListeners(Set<CacheEventListener> cacheEventListeners) {
|
||||
this.cacheEventListeners = cacheEventListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this cache should be marked as disabled.
|
||||
* @see net.sf.ehcache.Cache#setDisabled
|
||||
*/
|
||||
public void setDisabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws CacheException {
|
||||
// If no cache name given, use bean name as cache name.
|
||||
String cacheName = getName();
|
||||
if (cacheName == null) {
|
||||
cacheName = this.beanName;
|
||||
if (cacheName != null) {
|
||||
setName(cacheName);
|
||||
}
|
||||
}
|
||||
|
||||
// If no CacheManager given, fetch the default.
|
||||
if (this.cacheManager == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using default EhCache CacheManager for cache region '" + cacheName + "'");
|
||||
}
|
||||
this.cacheManager = CacheManager.getInstance();
|
||||
}
|
||||
|
||||
synchronized (this.cacheManager) {
|
||||
// Fetch cache region: If none with the given name exists, create one on the fly.
|
||||
Ehcache rawCache;
|
||||
boolean cacheExists = this.cacheManager.cacheExists(cacheName);
|
||||
|
||||
if (cacheExists) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using existing EhCache cache region '" + cacheName + "'");
|
||||
}
|
||||
rawCache = this.cacheManager.getEhcache(cacheName);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Creating new EhCache cache region '" + cacheName + "'");
|
||||
}
|
||||
rawCache = createCache();
|
||||
rawCache.setBootstrapCacheLoader(this.bootstrapCacheLoader);
|
||||
}
|
||||
|
||||
if (this.cacheEventListeners != null) {
|
||||
for (CacheEventListener listener : this.cacheEventListeners) {
|
||||
rawCache.getCacheEventNotificationService().registerListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
// Needs to happen after listener registration but before setStatisticsEnabled
|
||||
if (!cacheExists) {
|
||||
this.cacheManager.addCache(rawCache);
|
||||
}
|
||||
|
||||
if (this.disabled) {
|
||||
rawCache.setDisabled(true);
|
||||
}
|
||||
|
||||
Ehcache decoratedCache = decorateCache(rawCache);
|
||||
if (decoratedCache != rawCache) {
|
||||
this.cacheManager.replaceCacheWithDecoratedCache(rawCache, decoratedCache);
|
||||
}
|
||||
this.cache = decoratedCache;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a raw Cache object based on the configuration of this FactoryBean.
|
||||
*/
|
||||
protected Cache createCache() {
|
||||
return new Cache(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorate the given Cache, if necessary.
|
||||
* @param cache the raw Cache object, based on the configuration of this FactoryBean
|
||||
* @return the (potentially decorated) cache object to be registered with the CacheManager
|
||||
*/
|
||||
protected Ehcache decorateCache(Ehcache cache) {
|
||||
if (this.cacheEntryFactory != null) {
|
||||
if (this.cacheEntryFactory instanceof UpdatingCacheEntryFactory) {
|
||||
return new UpdatingSelfPopulatingCache(cache, (UpdatingCacheEntryFactory) this.cacheEntryFactory);
|
||||
}
|
||||
else {
|
||||
return new SelfPopulatingCache(cache, this.cacheEntryFactory);
|
||||
}
|
||||
}
|
||||
if (this.blocking) {
|
||||
return new BlockingCache(cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Ehcache getObject() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Predict the particular {@code Ehcache} implementation that will be returned from
|
||||
* {@link #getObject()} based on logic in {@link #createCache()} and
|
||||
* {@link #decorateCache(Ehcache)} as orchestrated by {@link #afterPropertiesSet()}.
|
||||
*/
|
||||
@Override
|
||||
public Class<? extends Ehcache> getObjectType() {
|
||||
if (this.cache != null) {
|
||||
return this.cache.getClass();
|
||||
}
|
||||
if (this.cacheEntryFactory != null) {
|
||||
if (this.cacheEntryFactory instanceof UpdatingCacheEntryFactory) {
|
||||
return UpdatingSelfPopulatingCache.class;
|
||||
}
|
||||
else {
|
||||
return SelfPopulatingCache.class;
|
||||
}
|
||||
}
|
||||
if (this.blocking) {
|
||||
return BlockingCache.class;
|
||||
}
|
||||
return Cache.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,199 +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.cache.ehcache;
|
||||
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.config.Configuration;
|
||||
import net.sf.ehcache.config.ConfigurationFactory;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} that exposes an EhCache {@link net.sf.ehcache.CacheManager}
|
||||
* instance (independent or shared), configured from a specified config location.
|
||||
*
|
||||
* <p>If no config location is specified, a CacheManager will be configured from
|
||||
* "ehcache.xml" in the root of the class path (that is, default EhCache initialization
|
||||
* - as defined in the EhCache docs - will apply).
|
||||
*
|
||||
* <p>Setting up a separate EhCacheManagerFactoryBean is also advisable when using
|
||||
* EhCacheFactoryBean, as it provides a (by default) independent CacheManager instance
|
||||
* and cares for proper shutdown of the CacheManager. EhCacheManagerFactoryBean is
|
||||
* also necessary for loading EhCache configuration from a non-default config location.
|
||||
*
|
||||
* <p>Note: As of Spring 5.0, Spring's EhCache support requires EhCache 2.10 or higher.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Dmitriy Kopylenko
|
||||
* @since 1.1.1
|
||||
* @see #setConfigLocation
|
||||
* @see #setShared
|
||||
* @see EhCacheFactoryBean
|
||||
* @see net.sf.ehcache.CacheManager
|
||||
*/
|
||||
public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, InitializingBean, DisposableBean {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@Nullable
|
||||
private Resource configLocation;
|
||||
|
||||
@Nullable
|
||||
private String cacheManagerName;
|
||||
|
||||
private boolean acceptExisting = false;
|
||||
|
||||
private boolean shared = false;
|
||||
|
||||
@Nullable
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private boolean locallyManaged = true;
|
||||
|
||||
|
||||
/**
|
||||
* Set the location of the EhCache config file. A typical value is "/WEB-INF/ehcache.xml".
|
||||
* <p>Default is "ehcache.xml" in the root of the class path, or if not found,
|
||||
* "ehcache-failsafe.xml" in the EhCache jar (default EhCache initialization).
|
||||
* @see net.sf.ehcache.CacheManager#create(java.io.InputStream)
|
||||
* @see net.sf.ehcache.CacheManager#CacheManager(java.io.InputStream)
|
||||
*/
|
||||
public void setConfigLocation(Resource configLocation) {
|
||||
this.configLocation = configLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the EhCache CacheManager (if a specific name is desired).
|
||||
* @see net.sf.ehcache.config.Configuration#setName(String)
|
||||
*/
|
||||
public void setCacheManagerName(String cacheManagerName) {
|
||||
this.cacheManagerName = cacheManagerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether an existing EhCache CacheManager of the same name will be accepted
|
||||
* for this EhCacheManagerFactoryBean setup. Default is "false".
|
||||
* <p>Typically used in combination with {@link #setCacheManagerName "cacheManagerName"}
|
||||
* but will simply work with the default CacheManager name if none specified.
|
||||
* All references to the same CacheManager name (or the same default) in the
|
||||
* same ClassLoader space will share the specified CacheManager then.
|
||||
* @see #setCacheManagerName
|
||||
* #see #setShared
|
||||
* @see net.sf.ehcache.CacheManager#getCacheManager(String)
|
||||
* @see net.sf.ehcache.CacheManager#CacheManager()
|
||||
*/
|
||||
public void setAcceptExisting(boolean acceptExisting) {
|
||||
this.acceptExisting = acceptExisting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the EhCache CacheManager should be shared (as a singleton at the
|
||||
* ClassLoader level) or independent (typically local within the application).
|
||||
* Default is "false", creating an independent local instance.
|
||||
* <p><b>NOTE:</b> This feature allows for sharing this EhCacheManagerFactoryBean's
|
||||
* CacheManager with any code calling <code>CacheManager.create()</code> in the same
|
||||
* ClassLoader space, with no need to agree on a specific CacheManager name.
|
||||
* However, it only supports a single EhCacheManagerFactoryBean involved which will
|
||||
* control the lifecycle of the underlying CacheManager (in particular, its shutdown).
|
||||
* <p>This flag overrides {@link #setAcceptExisting "acceptExisting"} if both are set,
|
||||
* since it indicates the 'stronger' mode of sharing.
|
||||
* @see #setCacheManagerName
|
||||
* @see #setAcceptExisting
|
||||
* @see net.sf.ehcache.CacheManager#create()
|
||||
* @see net.sf.ehcache.CacheManager#CacheManager()
|
||||
*/
|
||||
public void setShared(boolean shared) {
|
||||
this.shared = shared;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws CacheException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Initializing EhCache CacheManager" +
|
||||
(this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : ""));
|
||||
}
|
||||
|
||||
Configuration configuration = (this.configLocation != null ?
|
||||
EhCacheManagerUtils.parseConfiguration(this.configLocation) : ConfigurationFactory.parseConfiguration());
|
||||
if (this.cacheManagerName != null) {
|
||||
configuration.setName(this.cacheManagerName);
|
||||
}
|
||||
|
||||
if (this.shared) {
|
||||
// Old-school EhCache singleton sharing...
|
||||
// No way to find out whether we actually created a new CacheManager
|
||||
// or just received an existing singleton reference.
|
||||
this.cacheManager = CacheManager.create(configuration);
|
||||
}
|
||||
else if (this.acceptExisting) {
|
||||
// EhCache 2.5+: Reusing an existing CacheManager of the same name.
|
||||
// Basically the same code as in CacheManager.getInstance(String),
|
||||
// just storing whether we're dealing with an existing instance.
|
||||
synchronized (CacheManager.class) {
|
||||
this.cacheManager = CacheManager.getCacheManager(this.cacheManagerName);
|
||||
if (this.cacheManager == null) {
|
||||
this.cacheManager = new CacheManager(configuration);
|
||||
}
|
||||
else {
|
||||
this.locallyManaged = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Throwing an exception if a CacheManager of the same name exists already...
|
||||
this.cacheManager = new CacheManager(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CacheManager getObject() {
|
||||
return this.cacheManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends CacheManager> getObjectType() {
|
||||
return (this.cacheManager != null ? this.cacheManager.getClass() : CacheManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (this.cacheManager != null && this.locallyManaged) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Shutting down EhCache CacheManager" +
|
||||
(this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : ""));
|
||||
}
|
||||
this.cacheManager.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.cache.ehcache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.config.Configuration;
|
||||
import net.sf.ehcache.config.ConfigurationFactory;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Convenient builder methods for EhCache 2.5+ {@link CacheManager} setup,
|
||||
* providing easy programmatic bootstrapping from a Spring-provided resource.
|
||||
* This is primarily intended for use within {@code @Bean} methods in a
|
||||
* Spring configuration class.
|
||||
*
|
||||
* <p>These methods are a simple alternative to custom {@link CacheManager} setup
|
||||
* code. For any advanced purposes, consider using {@link #parseConfiguration},
|
||||
* customizing the configuration object, and then calling the
|
||||
* {@link CacheManager#CacheManager(Configuration)} constructor.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class EhCacheManagerUtils {
|
||||
|
||||
/**
|
||||
* Build an EhCache {@link CacheManager} from the default configuration.
|
||||
* <p>The CacheManager will be configured from "ehcache.xml" in the root of the class path
|
||||
* (that is, default EhCache initialization - as defined in the EhCache docs - will apply).
|
||||
* If no configuration file can be found, a fail-safe fallback configuration will be used.
|
||||
* @return the new EhCache CacheManager
|
||||
* @throws CacheException in case of configuration parsing failure
|
||||
*/
|
||||
public static CacheManager buildCacheManager() throws CacheException {
|
||||
return new CacheManager(ConfigurationFactory.parseConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an EhCache {@link CacheManager} from the default configuration.
|
||||
* <p>The CacheManager will be configured from "ehcache.xml" in the root of the class path
|
||||
* (that is, default EhCache initialization - as defined in the EhCache docs - will apply).
|
||||
* If no configuration file can be found, a fail-safe fallback configuration will be used.
|
||||
* @param name the desired name of the cache manager
|
||||
* @return the new EhCache CacheManager
|
||||
* @throws CacheException in case of configuration parsing failure
|
||||
*/
|
||||
public static CacheManager buildCacheManager(String name) throws CacheException {
|
||||
Configuration configuration = ConfigurationFactory.parseConfiguration();
|
||||
configuration.setName(name);
|
||||
return new CacheManager(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an EhCache {@link CacheManager} from the given configuration resource.
|
||||
* @param configLocation the location of the configuration file (as a Spring resource)
|
||||
* @return the new EhCache CacheManager
|
||||
* @throws CacheException in case of configuration parsing failure
|
||||
*/
|
||||
public static CacheManager buildCacheManager(Resource configLocation) throws CacheException {
|
||||
return new CacheManager(parseConfiguration(configLocation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an EhCache {@link CacheManager} from the given configuration resource.
|
||||
* @param name the desired name of the cache manager
|
||||
* @param configLocation the location of the configuration file (as a Spring resource)
|
||||
* @return the new EhCache CacheManager
|
||||
* @throws CacheException in case of configuration parsing failure
|
||||
*/
|
||||
public static CacheManager buildCacheManager(String name, Resource configLocation) throws CacheException {
|
||||
Configuration configuration = parseConfiguration(configLocation);
|
||||
configuration.setName(name);
|
||||
return new CacheManager(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse EhCache configuration from the given resource, for further use with
|
||||
* custom {@link CacheManager} creation.
|
||||
* @param configLocation the location of the configuration file (as a Spring resource)
|
||||
* @return the EhCache Configuration handle
|
||||
* @throws CacheException in case of configuration parsing failure
|
||||
* @see CacheManager#CacheManager(Configuration)
|
||||
* @see CacheManager#create(Configuration)
|
||||
*/
|
||||
public static Configuration parseConfiguration(Resource configLocation) throws CacheException {
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = configLocation.getInputStream();
|
||||
return ConfigurationFactory.parseConfiguration(is);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new CacheException("Failed to parse EhCache configuration resource", ex);
|
||||
}
|
||||
finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* Support classes for the open source cache
|
||||
* <a href="https://www.ehcache.org/">EhCache 2.x</a>,
|
||||
* allowing to set up an EhCache CacheManager and Caches
|
||||
* as beans in a Spring context.
|
||||
*
|
||||
* <p>Note: EhCache 3.x lives in a different package namespace
|
||||
* and is not covered by the traditional support classes here.
|
||||
* Instead, consider using it through JCache (JSR-107), with
|
||||
* Spring's support in {@code org.springframework.cache.jcache}.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.cache.ehcache;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
|
@ -104,7 +104,7 @@ public class MailSendException extends MailException {
|
|||
* be available after serialization as well.
|
||||
* @return the Map of failed messages as keys and thrown exceptions as values
|
||||
* @see SimpleMailMessage
|
||||
* @see javax.mail.internet.MimeMessage
|
||||
* @see jakarta.mail.internet.MimeMessage
|
||||
*/
|
||||
public final Map<Object, Exception> getFailedMessages() {
|
||||
return this.failedMessages;
|
||||
|
|
|
@ -20,8 +20,8 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import jakarta.activation.FileTypeMap;
|
||||
import jakarta.activation.MimetypesFileTypeMap;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
@ -58,7 +58,7 @@ import org.springframework.lang.Nullable;
|
|||
* @since 1.2
|
||||
* @see #setMappingLocation
|
||||
* @see #setMappings
|
||||
* @see javax.activation.MimetypesFileTypeMap
|
||||
* @see jakarta.activation.MimetypesFileTypeMap
|
||||
*/
|
||||
public class ConfigurableMimeFileTypeMap extends FileTypeMap implements InitializingBean {
|
||||
|
||||
|
@ -140,8 +140,8 @@ public class ConfigurableMimeFileTypeMap extends FileTypeMap implements Initiali
|
|||
* @param mappings an array of MIME type mapping lines (can be {@code null})
|
||||
* @return the compiled FileTypeMap
|
||||
* @throws IOException if resource access failed
|
||||
* @see javax.activation.MimetypesFileTypeMap#MimetypesFileTypeMap(java.io.InputStream)
|
||||
* @see javax.activation.MimetypesFileTypeMap#addMimeTypes(String)
|
||||
* @see jakarta.activation.MimetypesFileTypeMap#MimetypesFileTypeMap(java.io.InputStream)
|
||||
* @see jakarta.activation.MimetypesFileTypeMap#addMimeTypes(String)
|
||||
*/
|
||||
protected FileTypeMap createFileTypeMap(@Nullable Resource mappingLocation, @Nullable String[] mappings) throws IOException {
|
||||
MimetypesFileTypeMap fileTypeMap = null;
|
||||
|
|
|
@ -18,8 +18,8 @@ package org.springframework.mail.javamail;
|
|||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
@ -32,7 +32,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2.3
|
||||
* @see javax.mail.internet.InternetAddress
|
||||
* @see jakarta.mail.internet.InternetAddress
|
||||
*/
|
||||
public class InternetAddressEditor extends PropertyEditorSupport {
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ package org.springframework.mail.javamail;
|
|||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
|
||||
import org.springframework.mail.MailException;
|
||||
import org.springframework.mail.MailSender;
|
||||
|
@ -40,7 +40,7 @@ import org.springframework.mail.MailSender;
|
|||
* mechanism, possibly using a {@link MimeMessageHelper} for populating the message.
|
||||
* See {@link MimeMessageHelper MimeMessageHelper's javadoc} for an example.
|
||||
*
|
||||
* <p>The entire JavaMail {@link javax.mail.Session} management is abstracted
|
||||
* <p>The entire JavaMail {@link jakarta.mail.Session} management is abstracted
|
||||
* by the JavaMailSender. Client code should not deal with a Session in any way,
|
||||
* rather leave the entire JavaMail configuration and resource handling to the
|
||||
* JavaMailSender implementation. This also increases testability.
|
||||
|
@ -54,8 +54,8 @@ import org.springframework.mail.MailSender;
|
|||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 07.10.2003
|
||||
* @see javax.mail.internet.MimeMessage
|
||||
* @see javax.mail.Session
|
||||
* @see jakarta.mail.internet.MimeMessage
|
||||
* @see jakarta.mail.Session
|
||||
* @see JavaMailSenderImpl
|
||||
* @see MimeMessagePreparator
|
||||
* @see MimeMessageHelper
|
||||
|
|
|
@ -24,14 +24,14 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.mail.Address;
|
||||
import javax.mail.AuthenticationFailedException;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.NoSuchProviderException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import jakarta.activation.FileTypeMap;
|
||||
import jakarta.mail.Address;
|
||||
import jakarta.mail.AuthenticationFailedException;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.NoSuchProviderException;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Transport;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mail.MailAuthenticationException;
|
||||
|
@ -49,7 +49,7 @@ import org.springframework.util.Assert;
|
|||
* plain {@link org.springframework.mail.MailSender} implementation.
|
||||
*
|
||||
* <p>Allows for defining all settings locally as bean properties.
|
||||
* Alternatively, a pre-configured JavaMail {@link javax.mail.Session} can be
|
||||
* Alternatively, a pre-configured JavaMail {@link jakarta.mail.Session} can be
|
||||
* specified, possibly pulled from an application server's JNDI environment.
|
||||
*
|
||||
* <p>Non-default properties in this object will always override the settings
|
||||
|
@ -59,8 +59,8 @@ import org.springframework.util.Assert;
|
|||
* @author Dmitriy Kopylenko
|
||||
* @author Juergen Hoeller
|
||||
* @since 10.09.2003
|
||||
* @see javax.mail.internet.MimeMessage
|
||||
* @see javax.mail.Session
|
||||
* @see jakarta.mail.internet.MimeMessage
|
||||
* @see jakarta.mail.Session
|
||||
* @see #setSession
|
||||
* @see #setJavaMailProperties
|
||||
* @see #setHost
|
||||
|
@ -523,7 +523,7 @@ public class JavaMailSenderImpl implements JavaMailSender {
|
|||
* Obtain a Transport object from the given JavaMail Session,
|
||||
* using the configured protocol.
|
||||
* <p>Can be overridden in subclasses, e.g. to return a mock Transport object.
|
||||
* @see javax.mail.Session#getTransport(String)
|
||||
* @see jakarta.mail.Session#getTransport(String)
|
||||
* @see #getSession()
|
||||
* @see #getProtocol()
|
||||
*/
|
||||
|
|
|
@ -18,8 +18,8 @@ package org.springframework.mail.javamail;
|
|||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
|
||||
import org.springframework.mail.MailMessage;
|
||||
import org.springframework.mail.MailParseException;
|
||||
|
@ -35,7 +35,7 @@ import org.springframework.mail.MailParseException;
|
|||
* @author Juergen Hoeller
|
||||
* @since 1.1.5
|
||||
* @see MimeMessageHelper
|
||||
* @see javax.mail.internet.MimeMessage
|
||||
* @see jakarta.mail.internet.MimeMessage
|
||||
*/
|
||||
public class MimeMailMessage implements MailMessage {
|
||||
|
||||
|
|
|
@ -23,20 +23,20 @@ import java.io.OutputStream;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.activation.FileDataSource;
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.mail.internet.MimePart;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
import jakarta.activation.DataHandler;
|
||||
import jakarta.activation.DataSource;
|
||||
import jakarta.activation.FileDataSource;
|
||||
import jakarta.activation.FileTypeMap;
|
||||
import jakarta.mail.BodyPart;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import jakarta.mail.internet.MimeBodyPart;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.mail.internet.MimeMultipart;
|
||||
import jakarta.mail.internet.MimePart;
|
||||
import jakarta.mail.internet.MimeUtility;
|
||||
|
||||
import org.springframework.core.io.InputStreamSource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
@ -44,7 +44,7 @@ import org.springframework.lang.Nullable;
|
|||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper class for populating a {@link javax.mail.internet.MimeMessage}.
|
||||
* Helper class for populating a {@link jakarta.mail.internet.MimeMessage}.
|
||||
*
|
||||
* <p>Mirrors the simple setters of {@link org.springframework.mail.SimpleMailMessage},
|
||||
* directly applying the values to the underlying MimeMessage. Allows for defining
|
||||
|
@ -186,8 +186,8 @@ public class MimeMessageHelper {
|
|||
* the passed-in MimeMessage object, if carried there. Else,
|
||||
* JavaMail's default encoding will be used.
|
||||
* @param mimeMessage the mime message to work on
|
||||
* @see #MimeMessageHelper(javax.mail.internet.MimeMessage, boolean)
|
||||
* @see #getDefaultEncoding(javax.mail.internet.MimeMessage)
|
||||
* @see #MimeMessageHelper(jakarta.mail.internet.MimeMessage, boolean)
|
||||
* @see #getDefaultEncoding(jakarta.mail.internet.MimeMessage)
|
||||
* @see JavaMailSenderImpl#setDefaultEncoding
|
||||
*/
|
||||
public MimeMessageHelper(MimeMessage mimeMessage) {
|
||||
|
@ -200,7 +200,7 @@ public class MimeMessageHelper {
|
|||
* i.e. no alternative texts and no inline elements or attachments).
|
||||
* @param mimeMessage the mime message to work on
|
||||
* @param encoding the character encoding to use for the message
|
||||
* @see #MimeMessageHelper(javax.mail.internet.MimeMessage, boolean)
|
||||
* @see #MimeMessageHelper(jakarta.mail.internet.MimeMessage, boolean)
|
||||
*/
|
||||
public MimeMessageHelper(MimeMessage mimeMessage, @Nullable String encoding) {
|
||||
this.mimeMessage = mimeMessage;
|
||||
|
@ -223,8 +223,8 @@ public class MimeMessageHelper {
|
|||
* supports alternative texts, inline elements and attachments
|
||||
* (corresponds to MULTIPART_MODE_MIXED_RELATED)
|
||||
* @throws MessagingException if multipart creation failed
|
||||
* @see #MimeMessageHelper(javax.mail.internet.MimeMessage, int)
|
||||
* @see #getDefaultEncoding(javax.mail.internet.MimeMessage)
|
||||
* @see #MimeMessageHelper(jakarta.mail.internet.MimeMessage, int)
|
||||
* @see #getDefaultEncoding(jakarta.mail.internet.MimeMessage)
|
||||
* @see JavaMailSenderImpl#setDefaultEncoding
|
||||
*/
|
||||
public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart) throws MessagingException {
|
||||
|
@ -244,7 +244,7 @@ public class MimeMessageHelper {
|
|||
* (corresponds to MULTIPART_MODE_MIXED_RELATED)
|
||||
* @param encoding the character encoding to use for the message
|
||||
* @throws MessagingException if multipart creation failed
|
||||
* @see #MimeMessageHelper(javax.mail.internet.MimeMessage, int, String)
|
||||
* @see #MimeMessageHelper(jakarta.mail.internet.MimeMessage, int, String)
|
||||
*/
|
||||
public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart, @Nullable String encoding)
|
||||
throws MessagingException {
|
||||
|
@ -267,7 +267,7 @@ public class MimeMessageHelper {
|
|||
* @see #MULTIPART_MODE_MIXED
|
||||
* @see #MULTIPART_MODE_RELATED
|
||||
* @see #MULTIPART_MODE_MIXED_RELATED
|
||||
* @see #getDefaultEncoding(javax.mail.internet.MimeMessage)
|
||||
* @see #getDefaultEncoding(jakarta.mail.internet.MimeMessage)
|
||||
* @see JavaMailSenderImpl#setDefaultEncoding
|
||||
*/
|
||||
public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode) throws MessagingException {
|
||||
|
@ -388,7 +388,7 @@ public class MimeMessageHelper {
|
|||
* @throws IllegalStateException if this helper is not in multipart mode
|
||||
* @see #isMultipart
|
||||
* @see #getMimeMessage
|
||||
* @see javax.mail.internet.MimeMultipart#addBodyPart
|
||||
* @see jakarta.mail.internet.MimeMultipart#addBodyPart
|
||||
*/
|
||||
public final MimeMultipart getRootMimeMultipart() throws IllegalStateException {
|
||||
if (this.rootMimeMultipart == null) {
|
||||
|
@ -407,7 +407,7 @@ public class MimeMessageHelper {
|
|||
* @throws IllegalStateException if this helper is not in multipart mode
|
||||
* @see #isMultipart
|
||||
* @see #getRootMimeMultipart
|
||||
* @see javax.mail.internet.MimeMultipart#addBodyPart
|
||||
* @see jakarta.mail.internet.MimeMultipart#addBodyPart
|
||||
*/
|
||||
public final MimeMultipart getMimeMultipart() throws IllegalStateException {
|
||||
if (this.mimeMultipart == null) {
|
||||
|
@ -469,9 +469,9 @@ public class MimeMessageHelper {
|
|||
* {@code FileTypeMap} instance else.
|
||||
* @see #addInline
|
||||
* @see #addAttachment
|
||||
* @see #getDefaultFileTypeMap(javax.mail.internet.MimeMessage)
|
||||
* @see #getDefaultFileTypeMap(jakarta.mail.internet.MimeMessage)
|
||||
* @see JavaMailSenderImpl#setDefaultFileTypeMap
|
||||
* @see javax.activation.FileTypeMap#getDefaultFileTypeMap
|
||||
* @see jakarta.activation.FileTypeMap#getDefaultFileTypeMap
|
||||
* @see ConfigurableMimeFileTypeMap
|
||||
*/
|
||||
public void setFileTypeMap(@Nullable FileTypeMap fileTypeMap) {
|
||||
|
@ -538,7 +538,7 @@ public class MimeMessageHelper {
|
|||
* @param address the address to validate
|
||||
* @throws AddressException if validation failed
|
||||
* @see #isValidateAddresses()
|
||||
* @see javax.mail.internet.InternetAddress#validate()
|
||||
* @see jakarta.mail.internet.InternetAddress#validate()
|
||||
*/
|
||||
protected void validateAddress(InternetAddress address) throws AddressException {
|
||||
if (isValidateAddresses()) {
|
||||
|
@ -889,7 +889,7 @@ public class MimeMessageHelper {
|
|||
|
||||
/**
|
||||
* Add an inline element to the MimeMessage, taking the content from a
|
||||
* {@code javax.activation.DataSource}.
|
||||
* {@code jakarta.activation.DataSource}.
|
||||
* <p>Note that the InputStream returned by the DataSource implementation
|
||||
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
|
||||
* {@code getInputStream()} multiple times.
|
||||
|
@ -898,7 +898,7 @@ public class MimeMessageHelper {
|
|||
* @param contentId the content ID to use. Will end up as "Content-ID" header
|
||||
* in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
|
||||
* Can be referenced in HTML source via src="cid:myId" expressions.
|
||||
* @param dataSource the {@code javax.activation.DataSource} to take
|
||||
* @param dataSource the {@code jakarta.activation.DataSource} to take
|
||||
* the content from, determining the InputStream and the content type
|
||||
* @throws MessagingException in case of errors
|
||||
* @see #addInline(String, java.io.File)
|
||||
|
@ -929,7 +929,7 @@ public class MimeMessageHelper {
|
|||
* @throws MessagingException in case of errors
|
||||
* @see #setText
|
||||
* @see #addInline(String, org.springframework.core.io.Resource)
|
||||
* @see #addInline(String, javax.activation.DataSource)
|
||||
* @see #addInline(String, jakarta.activation.DataSource)
|
||||
*/
|
||||
public void addInline(String contentId, File file) throws MessagingException {
|
||||
Assert.notNull(file, "File must not be null");
|
||||
|
@ -956,7 +956,7 @@ public class MimeMessageHelper {
|
|||
* @throws MessagingException in case of errors
|
||||
* @see #setText
|
||||
* @see #addInline(String, java.io.File)
|
||||
* @see #addInline(String, javax.activation.DataSource)
|
||||
* @see #addInline(String, jakarta.activation.DataSource)
|
||||
*/
|
||||
public void addInline(String contentId, Resource resource) throws MessagingException {
|
||||
Assert.notNull(resource, "Resource must not be null");
|
||||
|
@ -984,7 +984,7 @@ public class MimeMessageHelper {
|
|||
* @see #setText
|
||||
* @see #getFileTypeMap
|
||||
* @see #addInline(String, org.springframework.core.io.Resource)
|
||||
* @see #addInline(String, javax.activation.DataSource)
|
||||
* @see #addInline(String, jakarta.activation.DataSource)
|
||||
*/
|
||||
public void addInline(String contentId, InputStreamSource inputStreamSource, String contentType)
|
||||
throws MessagingException {
|
||||
|
@ -1001,13 +1001,13 @@ public class MimeMessageHelper {
|
|||
|
||||
/**
|
||||
* Add an attachment to the MimeMessage, taking the content from a
|
||||
* {@code javax.activation.DataSource}.
|
||||
* {@code jakarta.activation.DataSource}.
|
||||
* <p>Note that the InputStream returned by the DataSource implementation
|
||||
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
|
||||
* {@code getInputStream()} multiple times.
|
||||
* @param attachmentFilename the name of the attachment as it will
|
||||
* appear in the mail (the content type will be determined by this)
|
||||
* @param dataSource the {@code javax.activation.DataSource} to take
|
||||
* @param dataSource the {@code jakarta.activation.DataSource} to take
|
||||
* the content from, determining the InputStream and the content type
|
||||
* @throws MessagingException in case of errors
|
||||
* @see #addAttachment(String, org.springframework.core.io.InputStreamSource)
|
||||
|
@ -1040,7 +1040,7 @@ public class MimeMessageHelper {
|
|||
* @param file the File resource to take the content from
|
||||
* @throws MessagingException in case of errors
|
||||
* @see #addAttachment(String, org.springframework.core.io.InputStreamSource)
|
||||
* @see #addAttachment(String, javax.activation.DataSource)
|
||||
* @see #addAttachment(String, jakarta.activation.DataSource)
|
||||
*/
|
||||
public void addAttachment(String attachmentFilename, File file) throws MessagingException {
|
||||
Assert.notNull(file, "File must not be null");
|
||||
|
@ -1064,7 +1064,7 @@ public class MimeMessageHelper {
|
|||
* (all of Spring's Resource implementations can be passed in here)
|
||||
* @throws MessagingException in case of errors
|
||||
* @see #addAttachment(String, java.io.File)
|
||||
* @see #addAttachment(String, javax.activation.DataSource)
|
||||
* @see #addAttachment(String, jakarta.activation.DataSource)
|
||||
* @see org.springframework.core.io.Resource
|
||||
*/
|
||||
public void addAttachment(String attachmentFilename, InputStreamSource inputStreamSource)
|
||||
|
@ -1087,7 +1087,7 @@ public class MimeMessageHelper {
|
|||
* @param contentType the content type to use for the element
|
||||
* @throws MessagingException in case of errors
|
||||
* @see #addAttachment(String, java.io.File)
|
||||
* @see #addAttachment(String, javax.activation.DataSource)
|
||||
* @see #addAttachment(String, jakarta.activation.DataSource)
|
||||
* @see org.springframework.core.io.Resource
|
||||
*/
|
||||
public void addAttachment(
|
||||
|
@ -1121,7 +1121,7 @@ public class MimeMessageHelper {
|
|||
}
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
throw new UnsupportedOperationException("Read-only javax.activation.DataSource");
|
||||
throw new UnsupportedOperationException("Read-only jakarta.activation.DataSource");
|
||||
}
|
||||
@Override
|
||||
public String getContentType() {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.mail.javamail;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
|
||||
/**
|
||||
* Callback interface for the preparation of JavaMail MIME messages.
|
||||
|
@ -42,7 +42,7 @@ public interface MimeMessagePreparator {
|
|||
/**
|
||||
* Prepare the given new MimeMessage instance.
|
||||
* @param mimeMessage the message to prepare
|
||||
* @throws javax.mail.MessagingException passing any exceptions thrown by MimeMessage
|
||||
* @throws jakarta.mail.MessagingException passing any exceptions thrown by MimeMessage
|
||||
* methods through for automatic conversion to the MailException hierarchy
|
||||
* @throws java.io.IOException passing any exceptions thrown by MimeMessage methods
|
||||
* through for automatic conversion to the MailException hierarchy
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
package org.springframework.mail.javamail;
|
||||
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import jakarta.activation.FileTypeMap;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
|
@ -34,8 +34,8 @@ import org.springframework.lang.Nullable;
|
|||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see JavaMailSenderImpl#createMimeMessage()
|
||||
* @see MimeMessageHelper#getDefaultEncoding(javax.mail.internet.MimeMessage)
|
||||
* @see MimeMessageHelper#getDefaultFileTypeMap(javax.mail.internet.MimeMessage)
|
||||
* @see MimeMessageHelper#getDefaultEncoding(jakarta.mail.internet.MimeMessage)
|
||||
* @see MimeMessageHelper#getDefaultFileTypeMap(jakarta.mail.internet.MimeMessage)
|
||||
*/
|
||||
class SmartMimeMessage extends MimeMessage {
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.scheduling.commonj;
|
||||
|
||||
import commonj.timers.Timer;
|
||||
import commonj.timers.TimerListener;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple TimerListener adapter that delegates to a given Runnable.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see commonj.timers.TimerListener
|
||||
* @see java.lang.Runnable
|
||||
* @deprecated as of 5.1, in favor of EE 7's
|
||||
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler}
|
||||
*/
|
||||
@Deprecated
|
||||
public class DelegatingTimerListener implements TimerListener {
|
||||
|
||||
private final Runnable runnable;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new DelegatingTimerListener.
|
||||
* @param runnable the Runnable implementation to delegate to
|
||||
*/
|
||||
public DelegatingTimerListener(Runnable runnable) {
|
||||
Assert.notNull(runnable, "Runnable is required");
|
||||
this.runnable = runnable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delegates execution to the underlying Runnable.
|
||||
*/
|
||||
@Override
|
||||
public void timerExpired(Timer timer) {
|
||||
this.runnable.run();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.scheduling.commonj;
|
||||
|
||||
import commonj.work.Work;
|
||||
|
||||
import org.springframework.scheduling.SchedulingAwareRunnable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple Work adapter that delegates to a given Runnable.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of 5.1, in favor of EE 7's
|
||||
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor}
|
||||
*/
|
||||
@Deprecated
|
||||
public class DelegatingWork implements Work {
|
||||
|
||||
private final Runnable delegate;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new DelegatingWork.
|
||||
* @param delegate the Runnable implementation to delegate to
|
||||
* (may be a SchedulingAwareRunnable for extended support)
|
||||
* @see org.springframework.scheduling.SchedulingAwareRunnable
|
||||
* @see #isDaemon()
|
||||
*/
|
||||
public DelegatingWork(Runnable delegate) {
|
||||
Assert.notNull(delegate, "Delegate must not be null");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the wrapped Runnable implementation.
|
||||
*/
|
||||
public final Runnable getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delegates execution to the underlying Runnable.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
this.delegate.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to
|
||||
* {@link org.springframework.scheduling.SchedulingAwareRunnable#isLongLived()},
|
||||
* if available.
|
||||
*/
|
||||
@Override
|
||||
public boolean isDaemon() {
|
||||
return (this.delegate instanceof SchedulingAwareRunnable &&
|
||||
((SchedulingAwareRunnable) this.delegate).isLongLived());
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation is empty, since we expect the Runnable
|
||||
* to terminate based on some specific shutdown signal.
|
||||
*/
|
||||
@Override
|
||||
public void release() {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.scheduling.commonj;
|
||||
|
||||
import commonj.timers.TimerListener;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* JavaBean that describes a scheduled TimerListener, consisting of
|
||||
* the TimerListener itself (or a Runnable to create a TimerListener for)
|
||||
* and a delay plus period. Period needs to be specified;
|
||||
* there is no point in a default for it.
|
||||
*
|
||||
* <p>The CommonJ TimerManager does not offer more sophisticated scheduling
|
||||
* options such as cron expressions. Consider using Quartz for such
|
||||
* advanced needs.
|
||||
*
|
||||
* <p>Note that the TimerManager uses a TimerListener instance that is
|
||||
* shared between repeated executions, in contrast to Quartz which
|
||||
* instantiates a new Job for each execution.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of 5.1, in favor of EE 7's
|
||||
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler}
|
||||
*/
|
||||
@Deprecated
|
||||
public class ScheduledTimerListener {
|
||||
|
||||
@Nullable
|
||||
private TimerListener timerListener;
|
||||
|
||||
private long delay = 0;
|
||||
|
||||
private long period = -1;
|
||||
|
||||
private boolean fixedRate = false;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ScheduledTimerListener,
|
||||
* to be populated via bean properties.
|
||||
* @see #setTimerListener
|
||||
* @see #setDelay
|
||||
* @see #setPeriod
|
||||
* @see #setFixedRate
|
||||
*/
|
||||
public ScheduledTimerListener() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ScheduledTimerListener, with default
|
||||
* one-time execution without delay.
|
||||
* @param timerListener the TimerListener to schedule
|
||||
*/
|
||||
public ScheduledTimerListener(TimerListener timerListener) {
|
||||
this.timerListener = timerListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ScheduledTimerListener, with default
|
||||
* one-time execution with the given delay.
|
||||
* @param timerListener the TimerListener to schedule
|
||||
* @param delay the delay before starting the task for the first time (ms)
|
||||
*/
|
||||
public ScheduledTimerListener(TimerListener timerListener, long delay) {
|
||||
this.timerListener = timerListener;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ScheduledTimerListener.
|
||||
* @param timerListener the TimerListener to schedule
|
||||
* @param delay the delay before starting the task for the first time (ms)
|
||||
* @param period the period between repeated task executions (ms)
|
||||
* @param fixedRate whether to schedule as fixed-rate execution
|
||||
*/
|
||||
public ScheduledTimerListener(TimerListener timerListener, long delay, long period, boolean fixedRate) {
|
||||
this.timerListener = timerListener;
|
||||
this.delay = delay;
|
||||
this.period = period;
|
||||
this.fixedRate = fixedRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ScheduledTimerListener, with default
|
||||
* one-time execution without delay.
|
||||
* @param timerTask the Runnable to schedule as TimerListener
|
||||
*/
|
||||
public ScheduledTimerListener(Runnable timerTask) {
|
||||
setRunnable(timerTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ScheduledTimerListener, with default
|
||||
* one-time execution with the given delay.
|
||||
* @param timerTask the Runnable to schedule as TimerListener
|
||||
* @param delay the delay before starting the task for the first time (ms)
|
||||
*/
|
||||
public ScheduledTimerListener(Runnable timerTask, long delay) {
|
||||
setRunnable(timerTask);
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ScheduledTimerListener.
|
||||
* @param timerTask the Runnable to schedule as TimerListener
|
||||
* @param delay the delay before starting the task for the first time (ms)
|
||||
* @param period the period between repeated task executions (ms)
|
||||
* @param fixedRate whether to schedule as fixed-rate execution
|
||||
*/
|
||||
public ScheduledTimerListener(Runnable timerTask, long delay, long period, boolean fixedRate) {
|
||||
setRunnable(timerTask);
|
||||
this.delay = delay;
|
||||
this.period = period;
|
||||
this.fixedRate = fixedRate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the Runnable to schedule as TimerListener.
|
||||
* @see DelegatingTimerListener
|
||||
*/
|
||||
public void setRunnable(Runnable timerTask) {
|
||||
this.timerListener = new DelegatingTimerListener(timerTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the TimerListener to schedule.
|
||||
*/
|
||||
public void setTimerListener(@Nullable TimerListener timerListener) {
|
||||
this.timerListener = timerListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TimerListener to schedule.
|
||||
*/
|
||||
@Nullable
|
||||
public TimerListener getTimerListener() {
|
||||
return this.timerListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delay before starting the task for the first time,
|
||||
* in milliseconds. Default is 0, immediately starting the
|
||||
* task after successful scheduling.
|
||||
* <p>If the "firstTime" property is specified, this property will be ignored.
|
||||
* Specify one or the other, not both.
|
||||
*/
|
||||
public void setDelay(long delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the delay before starting the job for the first time.
|
||||
*/
|
||||
public long getDelay() {
|
||||
return this.delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the period between repeated task executions, in milliseconds.
|
||||
* <p>Default is -1, leading to one-time execution. In case of zero or a
|
||||
* positive value, the task will be executed repeatedly, with the given
|
||||
* interval in-between executions.
|
||||
* <p>Note that the semantics of the period value vary between fixed-rate
|
||||
* and fixed-delay execution.
|
||||
* <p><b>Note:</b> A period of 0 (for example as fixed delay) <i>is</i>
|
||||
* supported, because the CommonJ specification defines this as a legal value.
|
||||
* Hence a value of 0 will result in immediate re-execution after a job has
|
||||
* finished (not in one-time execution like with {@code java.util.Timer}).
|
||||
* @see #setFixedRate
|
||||
* @see #isOneTimeTask()
|
||||
* @see commonj.timers.TimerManager#schedule(commonj.timers.TimerListener, long, long)
|
||||
*/
|
||||
public void setPeriod(long period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the period between repeated task executions.
|
||||
*/
|
||||
public long getPeriod() {
|
||||
return this.period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this task only ever going to execute once?
|
||||
* @return {@code true} if this task is only ever going to execute once
|
||||
* @see #getPeriod()
|
||||
*/
|
||||
public boolean isOneTimeTask() {
|
||||
return (this.period < 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to schedule as fixed-rate execution, rather than
|
||||
* fixed-delay execution. Default is "false", i.e. fixed delay.
|
||||
* <p>See TimerManager javadoc for details on those execution modes.
|
||||
* @see commonj.timers.TimerManager#schedule(commonj.timers.TimerListener, long, long)
|
||||
* @see commonj.timers.TimerManager#scheduleAtFixedRate(commonj.timers.TimerListener, long, long)
|
||||
*/
|
||||
public void setFixedRate(boolean fixedRate) {
|
||||
this.fixedRate = fixedRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to schedule as fixed-rate execution.
|
||||
*/
|
||||
public boolean isFixedRate() {
|
||||
return this.fixedRate;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,192 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.scheduling.commonj;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import commonj.timers.TimerManager;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.jndi.JndiLocatorSupport;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for classes that are accessing a CommonJ {@link commonj.timers.TimerManager}
|
||||
* Defines common configuration settings and common lifecycle handling.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see commonj.timers.TimerManager
|
||||
* @deprecated as of 5.1, in favor of EE 7's
|
||||
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler}
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class TimerManagerAccessor extends JndiLocatorSupport
|
||||
implements InitializingBean, DisposableBean, Lifecycle {
|
||||
|
||||
@Nullable
|
||||
private TimerManager timerManager;
|
||||
|
||||
@Nullable
|
||||
private String timerManagerName;
|
||||
|
||||
private boolean shared = false;
|
||||
|
||||
|
||||
/**
|
||||
* Specify the CommonJ TimerManager to delegate to.
|
||||
* <p>Note that the given TimerManager's lifecycle will be managed
|
||||
* by this FactoryBean.
|
||||
* <p>Alternatively (and typically), you can specify the JNDI name
|
||||
* of the target TimerManager.
|
||||
* @see #setTimerManagerName
|
||||
*/
|
||||
public void setTimerManager(TimerManager timerManager) {
|
||||
this.timerManager = timerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JNDI name of the CommonJ TimerManager.
|
||||
* <p>This can either be a fully qualified JNDI name, or the JNDI name relative
|
||||
* to the current environment naming context if "resourceRef" is set to "true".
|
||||
* @see #setTimerManager
|
||||
* @see #setResourceRef
|
||||
*/
|
||||
public void setTimerManagerName(String timerManagerName) {
|
||||
this.timerManagerName = timerManagerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the TimerManager obtained by this FactoryBean
|
||||
* is a shared instance ("true") or an independent instance ("false").
|
||||
* The lifecycle of the former is supposed to be managed by the application
|
||||
* server, while the lifecycle of the latter is up to the application.
|
||||
* <p>Default is "false", i.e. managing an independent TimerManager instance.
|
||||
* This is what the CommonJ specification suggests that application servers
|
||||
* are supposed to offer via JNDI lookups, typically declared as a
|
||||
* {@code resource-ref} of type {@code commonj.timers.TimerManager}
|
||||
* in {@code web.xml}, with {@code res-sharing-scope} set to 'Unshareable'.
|
||||
* <p>Switch this flag to "true" if you are obtaining a shared TimerManager,
|
||||
* typically through specifying the JNDI location of a TimerManager that
|
||||
* has been explicitly declared as 'Shareable'. Note that WebLogic's
|
||||
* cluster-aware Job Scheduler is a shared TimerManager too.
|
||||
* <p>The sole difference between this FactoryBean being in shared or
|
||||
* non-shared mode is that it will only attempt to suspend / resume / stop
|
||||
* the underlying TimerManager in case of an independent (non-shared) instance.
|
||||
* This only affects the {@link org.springframework.context.Lifecycle} support
|
||||
* as well as application context shutdown.
|
||||
* @see #stop()
|
||||
* @see #start()
|
||||
* @see #destroy()
|
||||
* @see commonj.timers.TimerManager
|
||||
*/
|
||||
public void setShared(boolean shared) {
|
||||
this.shared = shared;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws NamingException {
|
||||
if (this.timerManager == null) {
|
||||
if (this.timerManagerName == null) {
|
||||
throw new IllegalArgumentException("Either 'timerManager' or 'timerManagerName' must be specified");
|
||||
}
|
||||
this.timerManager = lookup(this.timerManagerName, TimerManager.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured TimerManager, if any.
|
||||
* @return the TimerManager, or {@code null} if not available
|
||||
*/
|
||||
@Nullable
|
||||
protected final TimerManager getTimerManager() {
|
||||
return this.timerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the TimerManager for actual use.
|
||||
* @return the TimerManager (never {@code null})
|
||||
* @throws IllegalStateException in case of no TimerManager set
|
||||
* @since 5.0
|
||||
*/
|
||||
protected TimerManager obtainTimerManager() {
|
||||
Assert.notNull(this.timerManager, "No TimerManager set");
|
||||
return this.timerManager;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of Lifecycle interface
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Resumes the underlying TimerManager (if not shared).
|
||||
* @see commonj.timers.TimerManager#resume()
|
||||
*/
|
||||
@Override
|
||||
public void start() {
|
||||
if (!this.shared) {
|
||||
obtainTimerManager().resume();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspends the underlying TimerManager (if not shared).
|
||||
* @see commonj.timers.TimerManager#suspend()
|
||||
*/
|
||||
@Override
|
||||
public void stop() {
|
||||
if (!this.shared) {
|
||||
obtainTimerManager().suspend();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers the underlying TimerManager as running if it is
|
||||
* neither suspending nor stopping.
|
||||
* @see commonj.timers.TimerManager#isSuspending()
|
||||
* @see commonj.timers.TimerManager#isStopping()
|
||||
*/
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
TimerManager tm = obtainTimerManager();
|
||||
return (!tm.isSuspending() && !tm.isStopping());
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of DisposableBean interface
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Stops the underlying TimerManager (if not shared).
|
||||
* @see commonj.timers.TimerManager#stop()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
// Stop the entire TimerManager, if necessary.
|
||||
if (this.timerManager != null && !this.shared) {
|
||||
// May return early, but at least we already cancelled all known Timers.
|
||||
this.timerManager.stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.scheduling.commonj;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import commonj.timers.Timer;
|
||||
import commonj.timers.TimerManager;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.FactoryBean} that retrieves a
|
||||
* CommonJ {@link commonj.timers.TimerManager} and exposes it for bean references.
|
||||
*
|
||||
* <p><b>This is the central convenience class for setting up a
|
||||
* CommonJ TimerManager in a Spring context.</b>
|
||||
*
|
||||
* <p>Allows for registration of ScheduledTimerListeners. This is the main
|
||||
* purpose of this class; the TimerManager itself could also be fetched
|
||||
* from JNDI via {@link org.springframework.jndi.JndiObjectFactoryBean}.
|
||||
* In scenarios that just require static registration of tasks at startup,
|
||||
* there is no need to access the TimerManager itself in application code.
|
||||
*
|
||||
* <p>Note that the TimerManager uses a TimerListener instance that is
|
||||
* shared between repeated executions, in contrast to Quartz which
|
||||
* instantiates a new Job for each execution.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see ScheduledTimerListener
|
||||
* @see commonj.timers.TimerManager
|
||||
* @see commonj.timers.TimerListener
|
||||
* @deprecated as of 5.1, in favor of EE 7's
|
||||
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler}
|
||||
*/
|
||||
@Deprecated
|
||||
public class TimerManagerFactoryBean extends TimerManagerAccessor
|
||||
implements FactoryBean<TimerManager>, InitializingBean, DisposableBean, Lifecycle {
|
||||
|
||||
@Nullable
|
||||
private ScheduledTimerListener[] scheduledTimerListeners;
|
||||
|
||||
@Nullable
|
||||
private List<Timer> timers;
|
||||
|
||||
|
||||
/**
|
||||
* Register a list of ScheduledTimerListener objects with the TimerManager
|
||||
* that this FactoryBean creates. Depending on each ScheduledTimerListener's settings,
|
||||
* it will be registered via one of TimerManager's schedule methods.
|
||||
* @see commonj.timers.TimerManager#schedule(commonj.timers.TimerListener, long)
|
||||
* @see commonj.timers.TimerManager#schedule(commonj.timers.TimerListener, long, long)
|
||||
* @see commonj.timers.TimerManager#scheduleAtFixedRate(commonj.timers.TimerListener, long, long)
|
||||
*/
|
||||
public void setScheduledTimerListeners(ScheduledTimerListener[] scheduledTimerListeners) {
|
||||
this.scheduledTimerListeners = scheduledTimerListeners;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of InitializingBean interface
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws NamingException {
|
||||
super.afterPropertiesSet();
|
||||
|
||||
if (this.scheduledTimerListeners != null) {
|
||||
this.timers = new ArrayList<>(this.scheduledTimerListeners.length);
|
||||
TimerManager timerManager = obtainTimerManager();
|
||||
for (ScheduledTimerListener scheduledTask : this.scheduledTimerListeners) {
|
||||
Timer timer;
|
||||
if (scheduledTask.isOneTimeTask()) {
|
||||
timer = timerManager.schedule(scheduledTask.getTimerListener(), scheduledTask.getDelay());
|
||||
}
|
||||
else {
|
||||
if (scheduledTask.isFixedRate()) {
|
||||
timer = timerManager.scheduleAtFixedRate(
|
||||
scheduledTask.getTimerListener(), scheduledTask.getDelay(), scheduledTask.getPeriod());
|
||||
}
|
||||
else {
|
||||
timer = timerManager.schedule(
|
||||
scheduledTask.getTimerListener(), scheduledTask.getDelay(), scheduledTask.getPeriod());
|
||||
}
|
||||
}
|
||||
this.timers.add(timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of FactoryBean interface
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public TimerManager getObject() {
|
||||
return getTimerManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends TimerManager> getObjectType() {
|
||||
TimerManager timerManager = getTimerManager();
|
||||
return (timerManager != null ? timerManager.getClass() : TimerManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of DisposableBean interface
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cancels all statically registered Timers on shutdown,
|
||||
* and stops the underlying TimerManager (if not shared).
|
||||
* @see commonj.timers.Timer#cancel()
|
||||
* @see commonj.timers.TimerManager#stop()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
// Cancel all registered timers.
|
||||
if (this.timers != null) {
|
||||
for (Timer timer : this.timers) {
|
||||
try {
|
||||
timer.cancel();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Could not cancel CommonJ Timer", ex);
|
||||
}
|
||||
}
|
||||
this.timers.clear();
|
||||
}
|
||||
|
||||
// Stop the TimerManager itself.
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,201 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.scheduling.commonj;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import commonj.timers.Timer;
|
||||
import commonj.timers.TimerListener;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.Trigger;
|
||||
import org.springframework.scheduling.support.SimpleTriggerContext;
|
||||
import org.springframework.scheduling.support.TaskUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ErrorHandler;
|
||||
|
||||
/**
|
||||
* Implementation of Spring's {@link TaskScheduler} interface, wrapping
|
||||
* a CommonJ {@link commonj.timers.TimerManager}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @since 3.0
|
||||
* @deprecated as of 5.1, in favor of EE 7's
|
||||
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler}
|
||||
*/
|
||||
@Deprecated
|
||||
public class TimerManagerTaskScheduler extends TimerManagerAccessor implements TaskScheduler {
|
||||
|
||||
@Nullable
|
||||
private volatile ErrorHandler errorHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Provide an {@link ErrorHandler} strategy.
|
||||
*/
|
||||
public void setErrorHandler(ErrorHandler errorHandler) {
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
|
||||
return new ReschedulingTimerListener(errorHandlingTask(task, true), trigger).schedule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
|
||||
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, false));
|
||||
Timer timer = obtainTimerManager().schedule(futureTask, startTime);
|
||||
futureTask.setTimer(timer);
|
||||
return futureTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
|
||||
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
|
||||
Timer timer = obtainTimerManager().scheduleAtFixedRate(futureTask, startTime, period);
|
||||
futureTask.setTimer(timer);
|
||||
return futureTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
|
||||
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
|
||||
Timer timer = obtainTimerManager().scheduleAtFixedRate(futureTask, 0, period);
|
||||
futureTask.setTimer(timer);
|
||||
return futureTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
|
||||
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
|
||||
Timer timer = obtainTimerManager().schedule(futureTask, startTime, delay);
|
||||
futureTask.setTimer(timer);
|
||||
return futureTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
|
||||
TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true));
|
||||
Timer timer = obtainTimerManager().schedule(futureTask, 0, delay);
|
||||
futureTask.setTimer(timer);
|
||||
return futureTask;
|
||||
}
|
||||
|
||||
private Runnable errorHandlingTask(Runnable delegate, boolean isRepeatingTask) {
|
||||
return TaskUtils.decorateTaskWithErrorHandler(delegate, this.errorHandler, isRepeatingTask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ScheduledFuture adapter that wraps a CommonJ Timer.
|
||||
*/
|
||||
private static class TimerScheduledFuture extends FutureTask<Object> implements TimerListener, ScheduledFuture<Object> {
|
||||
|
||||
@Nullable
|
||||
protected transient Timer timer;
|
||||
|
||||
protected transient boolean cancelled = false;
|
||||
|
||||
public TimerScheduledFuture(Runnable runnable) {
|
||||
super(runnable, null);
|
||||
}
|
||||
|
||||
public void setTimer(Timer timer) {
|
||||
this.timer = timer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timerExpired(Timer timer) {
|
||||
runAndReset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
boolean result = super.cancel(mayInterruptIfRunning);
|
||||
if (this.timer != null) {
|
||||
this.timer.cancel();
|
||||
}
|
||||
this.cancelled = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit unit) {
|
||||
Assert.state(this.timer != null, "No Timer available");
|
||||
return unit.convert(this.timer.getScheduledExecutionTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Delayed other) {
|
||||
if (this == other) {
|
||||
return 0;
|
||||
}
|
||||
long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS);
|
||||
return (diff == 0 ? 0 : ((diff < 0) ? -1 : 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ScheduledFuture adapter for trigger-based rescheduling.
|
||||
*/
|
||||
private class ReschedulingTimerListener extends TimerScheduledFuture {
|
||||
|
||||
private final Trigger trigger;
|
||||
|
||||
private final SimpleTriggerContext triggerContext = new SimpleTriggerContext();
|
||||
|
||||
private volatile Date scheduledExecutionTime = new Date();
|
||||
|
||||
public ReschedulingTimerListener(Runnable runnable, Trigger trigger) {
|
||||
super(runnable);
|
||||
this.trigger = trigger;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ScheduledFuture<?> schedule() {
|
||||
Date nextExecutionTime = this.trigger.nextExecutionTime(this.triggerContext);
|
||||
if (nextExecutionTime == null) {
|
||||
return null;
|
||||
}
|
||||
this.scheduledExecutionTime = nextExecutionTime;
|
||||
setTimer(obtainTimerManager().schedule(this, this.scheduledExecutionTime));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timerExpired(Timer timer) {
|
||||
Date actualExecutionTime = new Date();
|
||||
super.timerExpired(timer);
|
||||
Date completionTime = new Date();
|
||||
this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
|
||||
if (!this.cancelled) {
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.scheduling.commonj;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import commonj.work.Work;
|
||||
import commonj.work.WorkException;
|
||||
import commonj.work.WorkItem;
|
||||
import commonj.work.WorkListener;
|
||||
import commonj.work.WorkManager;
|
||||
import commonj.work.WorkRejectedException;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.core.task.TaskDecorator;
|
||||
import org.springframework.core.task.TaskRejectedException;
|
||||
import org.springframework.jndi.JndiLocatorSupport;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.scheduling.SchedulingException;
|
||||
import org.springframework.scheduling.SchedulingTaskExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
|
||||
/**
|
||||
* TaskExecutor implementation that delegates to a CommonJ WorkManager,
|
||||
* implementing the {@link commonj.work.WorkManager} interface,
|
||||
* which either needs to be specified as reference or through the JNDI name.
|
||||
*
|
||||
* <p><b>This is the central convenience class for setting up a
|
||||
* CommonJ WorkManager in a Spring context.</b>
|
||||
*
|
||||
* <p>Also implements the CommonJ WorkManager interface itself, delegating all
|
||||
* calls to the target WorkManager. Hence, a caller can choose whether it wants
|
||||
* to talk to this executor through the Spring TaskExecutor interface or the
|
||||
* CommonJ WorkManager interface.
|
||||
*
|
||||
* <p>The CommonJ WorkManager will usually be retrieved from the application
|
||||
* server's JNDI environment, as defined in the server's management console.
|
||||
*
|
||||
* <p>Note: On EE 7/8 compliant versions of WebLogic and WebSphere, a
|
||||
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor}
|
||||
* should be preferred, following JSR-236 support in Java EE 7/8.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of 5.1, in favor of the EE 7/8 based
|
||||
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor}
|
||||
*/
|
||||
@Deprecated
|
||||
public class WorkManagerTaskExecutor extends JndiLocatorSupport
|
||||
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, WorkManager, InitializingBean {
|
||||
|
||||
@Nullable
|
||||
private WorkManager workManager;
|
||||
|
||||
@Nullable
|
||||
private String workManagerName;
|
||||
|
||||
@Nullable
|
||||
private WorkListener workListener;
|
||||
|
||||
@Nullable
|
||||
private TaskDecorator taskDecorator;
|
||||
|
||||
|
||||
/**
|
||||
* Specify the CommonJ WorkManager to delegate to.
|
||||
* <p>Alternatively, you can also specify the JNDI name of the target WorkManager.
|
||||
* @see #setWorkManagerName
|
||||
*/
|
||||
public void setWorkManager(WorkManager workManager) {
|
||||
this.workManager = workManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JNDI name of the CommonJ WorkManager.
|
||||
* <p>This can either be a fully qualified JNDI name, or the JNDI name relative
|
||||
* to the current environment naming context if "resourceRef" is set to "true".
|
||||
* @see #setWorkManager
|
||||
* @see #setResourceRef
|
||||
*/
|
||||
public void setWorkManagerName(String workManagerName) {
|
||||
this.workManagerName = workManagerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a CommonJ WorkListener to apply, if any.
|
||||
* <p>This shared WorkListener instance will be passed on to the
|
||||
* WorkManager by all {@link #execute} calls on this TaskExecutor.
|
||||
*/
|
||||
public void setWorkListener(WorkListener workListener) {
|
||||
this.workListener = workListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
|
||||
* about to be executed.
|
||||
* <p>Note that such a decorator is not necessarily being applied to the
|
||||
* user-supplied {@code Runnable}/{@code Callable} but rather to the actual
|
||||
* execution callback (which may be a wrapper around the user-supplied task).
|
||||
* <p>The primary use case is to set some execution context around the task's
|
||||
* invocation, or to provide some monitoring/statistics for task execution.
|
||||
* <p><b>NOTE:</b> Exception handling in {@code TaskDecorator} implementations
|
||||
* is limited to plain {@code Runnable} execution via {@code execute} calls.
|
||||
* In case of {@code #submit} calls, the exposed {@code Runnable} will be a
|
||||
* {@code FutureTask} which does not propagate any exceptions; you might
|
||||
* have to cast it and call {@code Future#get} to evaluate exceptions.
|
||||
* @since 4.3
|
||||
*/
|
||||
public void setTaskDecorator(TaskDecorator taskDecorator) {
|
||||
this.taskDecorator = taskDecorator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws NamingException {
|
||||
if (this.workManager == null) {
|
||||
if (this.workManagerName == null) {
|
||||
throw new IllegalArgumentException("Either 'workManager' or 'workManagerName' must be specified");
|
||||
}
|
||||
this.workManager = lookup(this.workManagerName, WorkManager.class);
|
||||
}
|
||||
}
|
||||
|
||||
private WorkManager obtainWorkManager() {
|
||||
Assert.state(this.workManager != null, "No WorkManager specified");
|
||||
return this.workManager;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Implementation of the Spring SchedulingTaskExecutor interface
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task) {
|
||||
Work work = new DelegatingWork(this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
|
||||
try {
|
||||
if (this.workListener != null) {
|
||||
obtainWorkManager().schedule(work, this.workListener);
|
||||
}
|
||||
else {
|
||||
obtainWorkManager().schedule(work);
|
||||
}
|
||||
}
|
||||
catch (WorkRejectedException ex) {
|
||||
throw new TaskRejectedException("CommonJ WorkManager did not accept task: " + task, ex);
|
||||
}
|
||||
catch (WorkException ex) {
|
||||
throw new SchedulingException("Could not schedule task on CommonJ WorkManager", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task, long startTimeout) {
|
||||
execute(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> submit(Runnable task) {
|
||||
FutureTask<Object> future = new FutureTask<>(task, null);
|
||||
execute(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<T> submit(Callable<T> task) {
|
||||
FutureTask<T> future = new FutureTask<>(task);
|
||||
execute(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> submitListenable(Runnable task) {
|
||||
ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
|
||||
execute(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
|
||||
ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
|
||||
execute(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Implementation of the CommonJ WorkManager interface
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public WorkItem schedule(Work work) throws WorkException, IllegalArgumentException {
|
||||
return obtainWorkManager().schedule(work);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkItem schedule(Work work, WorkListener workListener) throws WorkException {
|
||||
return obtainWorkManager().schedule(work, workListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public boolean waitForAll(Collection workItems, long timeout) throws InterruptedException {
|
||||
return obtainWorkManager().waitForAll(workItems, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Collection waitForAny(Collection workItems, long timeout) throws InterruptedException {
|
||||
return obtainWorkManager().waitForAny(workItems, timeout);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
/**
|
||||
* Convenience classes for scheduling based on the CommonJ WorkManager/TimerManager
|
||||
* facility, as supported by IBM WebSphere 6.0+ and BEA WebLogic 9.0+.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.scheduling.commonj;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.cache.ehcache;
|
||||
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.config.CacheConfiguration;
|
||||
import net.sf.ehcache.config.Configuration;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManagerTests;
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class EhCacheCacheManagerTests extends AbstractTransactionSupportingCacheManagerTests<EhCacheCacheManager> {
|
||||
|
||||
private CacheManager nativeCacheManager;
|
||||
|
||||
private EhCacheCacheManager cacheManager;
|
||||
|
||||
private EhCacheCacheManager transactionalCacheManager;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
nativeCacheManager = new CacheManager(new Configuration().name("EhCacheCacheManagerTests")
|
||||
.defaultCache(new CacheConfiguration("default", 100)));
|
||||
addNativeCache(CACHE_NAME);
|
||||
|
||||
cacheManager = new EhCacheCacheManager(nativeCacheManager);
|
||||
cacheManager.setTransactionAware(false);
|
||||
cacheManager.afterPropertiesSet();
|
||||
|
||||
transactionalCacheManager = new EhCacheCacheManager(nativeCacheManager);
|
||||
transactionalCacheManager.setTransactionAware(true);
|
||||
transactionalCacheManager.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void shutdown() {
|
||||
nativeCacheManager.shutdown();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected EhCacheCacheManager getCacheManager(boolean transactionAware) {
|
||||
if (transactionAware) {
|
||||
return transactionalCacheManager;
|
||||
}
|
||||
else {
|
||||
return cacheManager;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends org.springframework.cache.Cache> getCacheType() {
|
||||
return EhCacheCache.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNativeCache(String cacheName) {
|
||||
nativeCacheManager.addCache(cacheName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNativeCache(String cacheName) {
|
||||
nativeCacheManager.removeCache(cacheName);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.cache.ehcache;
|
||||
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
import net.sf.ehcache.config.CacheConfiguration;
|
||||
import net.sf.ehcache.config.Configuration;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.testfixture.cache.AbstractCacheTests;
|
||||
import org.springframework.core.testfixture.EnabledForTestGroups;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
|
||||
|
||||
/**
|
||||
* @author Costin Leau
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class EhCacheCacheTests extends AbstractCacheTests<EhCacheCache> {
|
||||
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private Ehcache nativeCache;
|
||||
|
||||
private EhCacheCache cache;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
cacheManager = new CacheManager(new Configuration().name("EhCacheCacheTests")
|
||||
.defaultCache(new CacheConfiguration("default", 100)));
|
||||
nativeCache = new net.sf.ehcache.Cache(new CacheConfiguration(CACHE_NAME, 100));
|
||||
cacheManager.addCache(nativeCache);
|
||||
|
||||
cache = new EhCacheCache(nativeCache);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void shutdown() {
|
||||
cacheManager.shutdown();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected EhCacheCache getCache() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Ehcache getNativeCache() {
|
||||
return nativeCache;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
public void testExpiredElements() throws Exception {
|
||||
String key = "brancusi";
|
||||
String value = "constantin";
|
||||
Element brancusi = new Element(key, value);
|
||||
// ttl = 10s
|
||||
brancusi.setTimeToLive(3);
|
||||
nativeCache.put(brancusi);
|
||||
|
||||
assertThat(cache.get(key).get()).isEqualTo(value);
|
||||
// wait for the entry to expire
|
||||
Thread.sleep(5 * 1000);
|
||||
assertThat(cache.get(key)).isNull();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,287 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.cache.ehcache;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.config.CacheConfiguration;
|
||||
import net.sf.ehcache.constructs.blocking.BlockingCache;
|
||||
import net.sf.ehcache.constructs.blocking.SelfPopulatingCache;
|
||||
import net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory;
|
||||
import net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Dmitriy Kopylenko
|
||||
* @since 27.09.2004
|
||||
*/
|
||||
public class EhCacheSupportTests {
|
||||
|
||||
@Test
|
||||
public void testBlankCacheManager() {
|
||||
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
|
||||
cacheManagerFb.setCacheManagerName("myCacheManager");
|
||||
assertThat(cacheManagerFb.getObjectType()).isEqualTo(CacheManager.class);
|
||||
assertThat(cacheManagerFb.isSingleton()).as("Singleton property").isTrue();
|
||||
cacheManagerFb.afterPropertiesSet();
|
||||
try {
|
||||
CacheManager cm = cacheManagerFb.getObject();
|
||||
assertThat(cm.getCacheNames().length == 0).as("Loaded CacheManager with no caches").isTrue();
|
||||
Cache myCache1 = cm.getCache("myCache1");
|
||||
assertThat(myCache1 == null).as("No myCache1 defined").isTrue();
|
||||
}
|
||||
finally {
|
||||
cacheManagerFb.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheManagerConflict() {
|
||||
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
|
||||
try {
|
||||
cacheManagerFb.setCacheManagerName("myCacheManager");
|
||||
assertThat(cacheManagerFb.getObjectType()).isEqualTo(CacheManager.class);
|
||||
assertThat(cacheManagerFb.isSingleton()).as("Singleton property").isTrue();
|
||||
cacheManagerFb.afterPropertiesSet();
|
||||
CacheManager cm = cacheManagerFb.getObject();
|
||||
assertThat(cm.getCacheNames().length == 0).as("Loaded CacheManager with no caches").isTrue();
|
||||
Cache myCache1 = cm.getCache("myCache1");
|
||||
assertThat(myCache1 == null).as("No myCache1 defined").isTrue();
|
||||
|
||||
EhCacheManagerFactoryBean cacheManagerFb2 = new EhCacheManagerFactoryBean();
|
||||
cacheManagerFb2.setCacheManagerName("myCacheManager");
|
||||
assertThatExceptionOfType(CacheException.class).as("because of naming conflict").isThrownBy(
|
||||
cacheManagerFb2::afterPropertiesSet);
|
||||
}
|
||||
finally {
|
||||
cacheManagerFb.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptExistingCacheManager() {
|
||||
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
|
||||
cacheManagerFb.setCacheManagerName("myCacheManager");
|
||||
assertThat(cacheManagerFb.getObjectType()).isEqualTo(CacheManager.class);
|
||||
assertThat(cacheManagerFb.isSingleton()).as("Singleton property").isTrue();
|
||||
cacheManagerFb.afterPropertiesSet();
|
||||
try {
|
||||
CacheManager cm = cacheManagerFb.getObject();
|
||||
assertThat(cm.getCacheNames().length == 0).as("Loaded CacheManager with no caches").isTrue();
|
||||
Cache myCache1 = cm.getCache("myCache1");
|
||||
assertThat(myCache1 == null).as("No myCache1 defined").isTrue();
|
||||
|
||||
EhCacheManagerFactoryBean cacheManagerFb2 = new EhCacheManagerFactoryBean();
|
||||
cacheManagerFb2.setCacheManagerName("myCacheManager");
|
||||
cacheManagerFb2.setAcceptExisting(true);
|
||||
cacheManagerFb2.afterPropertiesSet();
|
||||
CacheManager cm2 = cacheManagerFb2.getObject();
|
||||
assertThat(cm2).isSameAs(cm);
|
||||
cacheManagerFb2.destroy();
|
||||
}
|
||||
finally {
|
||||
cacheManagerFb.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public void testCacheManagerFromConfigFile() {
|
||||
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
|
||||
cacheManagerFb.setConfigLocation(new ClassPathResource("testEhcache.xml", getClass()));
|
||||
cacheManagerFb.setCacheManagerName("myCacheManager");
|
||||
cacheManagerFb.afterPropertiesSet();
|
||||
try {
|
||||
CacheManager cm = cacheManagerFb.getObject();
|
||||
assertThat(cm.getCacheNames().length == 1).as("Correct number of caches loaded").isTrue();
|
||||
Cache myCache1 = cm.getCache("myCache1");
|
||||
assertThat(myCache1.getCacheConfiguration().isEternal()).as("myCache1 is not eternal").isFalse();
|
||||
assertThat(myCache1.getCacheConfiguration().getMaxEntriesLocalHeap() == 300).as("myCache1.maxElements == 300").isTrue();
|
||||
}
|
||||
finally {
|
||||
cacheManagerFb.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEhCacheFactoryBeanWithDefaultCacheManager() {
|
||||
doTestEhCacheFactoryBean(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEhCacheFactoryBeanWithExplicitCacheManager() {
|
||||
doTestEhCacheFactoryBean(true);
|
||||
}
|
||||
|
||||
private void doTestEhCacheFactoryBean(boolean useCacheManagerFb) {
|
||||
Cache cache;
|
||||
EhCacheManagerFactoryBean cacheManagerFb = null;
|
||||
boolean cacheManagerFbInitialized = false;
|
||||
try {
|
||||
EhCacheFactoryBean cacheFb = new EhCacheFactoryBean();
|
||||
Class<? extends Ehcache> objectType = cacheFb.getObjectType();
|
||||
assertThat(Ehcache.class.isAssignableFrom(objectType)).isTrue();
|
||||
assertThat(cacheFb.isSingleton()).as("Singleton property").isTrue();
|
||||
if (useCacheManagerFb) {
|
||||
cacheManagerFb = new EhCacheManagerFactoryBean();
|
||||
cacheManagerFb.setConfigLocation(new ClassPathResource("testEhcache.xml", getClass()));
|
||||
cacheManagerFb.setCacheManagerName("cache");
|
||||
cacheManagerFb.afterPropertiesSet();
|
||||
cacheManagerFbInitialized = true;
|
||||
cacheFb.setCacheManager(cacheManagerFb.getObject());
|
||||
}
|
||||
|
||||
cacheFb.setCacheName("myCache1");
|
||||
cacheFb.afterPropertiesSet();
|
||||
cache = (Cache) cacheFb.getObject();
|
||||
Class<? extends Ehcache> objectType2 = cacheFb.getObjectType();
|
||||
assertThat(objectType2).isSameAs(objectType);
|
||||
CacheConfiguration config = cache.getCacheConfiguration();
|
||||
assertThat(cache.getName()).isEqualTo("myCache1");
|
||||
if (useCacheManagerFb){
|
||||
assertThat(config.getMaxEntriesLocalHeap()).as("myCache1.maxElements").isEqualTo(300);
|
||||
}
|
||||
else {
|
||||
assertThat(config.getMaxEntriesLocalHeap()).as("myCache1.maxElements").isEqualTo(10000);
|
||||
}
|
||||
|
||||
// Cache region is not defined. Should create one with default properties.
|
||||
cacheFb = new EhCacheFactoryBean();
|
||||
if (useCacheManagerFb) {
|
||||
cacheFb.setCacheManager(cacheManagerFb.getObject());
|
||||
}
|
||||
cacheFb.setCacheName("undefinedCache");
|
||||
cacheFb.afterPropertiesSet();
|
||||
cache = (Cache) cacheFb.getObject();
|
||||
config = cache.getCacheConfiguration();
|
||||
assertThat(cache.getName()).isEqualTo("undefinedCache");
|
||||
assertThat(config.getMaxEntriesLocalHeap() == 10000).as("default maxElements is correct").isTrue();
|
||||
assertThat(config.isEternal()).as("default eternal is correct").isFalse();
|
||||
assertThat(config.getTimeToLiveSeconds() == 120).as("default timeToLive is correct").isTrue();
|
||||
assertThat(config.getTimeToIdleSeconds() == 120).as("default timeToIdle is correct").isTrue();
|
||||
assertThat(config.getDiskExpiryThreadIntervalSeconds() == 120).as("default diskExpiryThreadIntervalSeconds is correct").isTrue();
|
||||
|
||||
// overriding the default properties
|
||||
cacheFb = new EhCacheFactoryBean();
|
||||
if (useCacheManagerFb) {
|
||||
cacheFb.setCacheManager(cacheManagerFb.getObject());
|
||||
}
|
||||
cacheFb.setBeanName("undefinedCache2");
|
||||
cacheFb.setMaxEntriesLocalHeap(5);
|
||||
cacheFb.setTimeToLive(8);
|
||||
cacheFb.setTimeToIdle(7);
|
||||
cacheFb.setDiskExpiryThreadIntervalSeconds(10);
|
||||
cacheFb.afterPropertiesSet();
|
||||
cache = (Cache) cacheFb.getObject();
|
||||
config = cache.getCacheConfiguration();
|
||||
|
||||
assertThat(cache.getName()).isEqualTo("undefinedCache2");
|
||||
assertThat(config.getMaxEntriesLocalHeap() == 5).as("overridden maxElements is correct").isTrue();
|
||||
assertThat(config.getTimeToLiveSeconds() == 8).as("default timeToLive is correct").isTrue();
|
||||
assertThat(config.getTimeToIdleSeconds() == 7).as("default timeToIdle is correct").isTrue();
|
||||
assertThat(config.getDiskExpiryThreadIntervalSeconds() == 10).as("overridden diskExpiryThreadIntervalSeconds is correct").isTrue();
|
||||
}
|
||||
finally {
|
||||
if (cacheManagerFbInitialized) {
|
||||
cacheManagerFb.destroy();
|
||||
}
|
||||
else {
|
||||
CacheManager.getInstance().shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEhCacheFactoryBeanWithBlockingCache() {
|
||||
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
|
||||
cacheManagerFb.afterPropertiesSet();
|
||||
try {
|
||||
CacheManager cm = cacheManagerFb.getObject();
|
||||
EhCacheFactoryBean cacheFb = new EhCacheFactoryBean();
|
||||
cacheFb.setCacheManager(cm);
|
||||
cacheFb.setCacheName("myCache1");
|
||||
cacheFb.setBlocking(true);
|
||||
assertThat(BlockingCache.class).isEqualTo(cacheFb.getObjectType());
|
||||
cacheFb.afterPropertiesSet();
|
||||
Ehcache myCache1 = cm.getEhcache("myCache1");
|
||||
boolean condition = myCache1 instanceof BlockingCache;
|
||||
assertThat(condition).isTrue();
|
||||
}
|
||||
finally {
|
||||
cacheManagerFb.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEhCacheFactoryBeanWithSelfPopulatingCache() {
|
||||
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
|
||||
cacheManagerFb.afterPropertiesSet();
|
||||
try {
|
||||
CacheManager cm = cacheManagerFb.getObject();
|
||||
EhCacheFactoryBean cacheFb = new EhCacheFactoryBean();
|
||||
cacheFb.setCacheManager(cm);
|
||||
cacheFb.setCacheName("myCache1");
|
||||
cacheFb.setCacheEntryFactory(key -> key);
|
||||
assertThat(SelfPopulatingCache.class).isEqualTo(cacheFb.getObjectType());
|
||||
cacheFb.afterPropertiesSet();
|
||||
Ehcache myCache1 = cm.getEhcache("myCache1");
|
||||
boolean condition = myCache1 instanceof SelfPopulatingCache;
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(myCache1.get("myKey1").getObjectValue()).isEqualTo("myKey1");
|
||||
}
|
||||
finally {
|
||||
cacheManagerFb.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEhCacheFactoryBeanWithUpdatingSelfPopulatingCache() {
|
||||
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
|
||||
cacheManagerFb.afterPropertiesSet();
|
||||
try {
|
||||
CacheManager cm = cacheManagerFb.getObject();
|
||||
EhCacheFactoryBean cacheFb = new EhCacheFactoryBean();
|
||||
cacheFb.setCacheManager(cm);
|
||||
cacheFb.setCacheName("myCache1");
|
||||
cacheFb.setCacheEntryFactory(new UpdatingCacheEntryFactory() {
|
||||
@Override
|
||||
public Object createEntry(Object key) {
|
||||
return key;
|
||||
}
|
||||
@Override
|
||||
public void updateEntryValue(Object key, Object value) {
|
||||
}
|
||||
});
|
||||
assertThat(UpdatingSelfPopulatingCache.class).isEqualTo(cacheFb.getObjectType());
|
||||
cacheFb.afterPropertiesSet();
|
||||
Ehcache myCache1 = cm.getEhcache("myCache1");
|
||||
boolean condition = myCache1 instanceof UpdatingSelfPopulatingCache;
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(myCache1.get("myKey1").getObjectValue()).isEqualTo("myKey1");
|
||||
}
|
||||
finally {
|
||||
cacheManagerFb.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.cache.jcache;
|
||||
|
||||
import javax.cache.Caching;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
|
||||
/**
|
||||
* Just here to be run against EHCache 3, whereas the original JCacheEhCacheAnnotationTests
|
||||
* runs against EhCache 2.x with the EhCache-JCache add-on.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class JCacheEhCache3AnnotationTests extends JCacheEhCacheAnnotationTests {
|
||||
|
||||
@Override
|
||||
protected CachingProvider getCachingProvider() {
|
||||
return Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.cache.jcache;
|
||||
|
||||
import javax.cache.Caching;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
|
||||
/**
|
||||
* Just here to be run against EHCache 3, whereas the original JCacheEhCacheAnnotationTests
|
||||
* runs against EhCache 2.x with the EhCache-JCache add-on.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class JCacheEhCache3ApiTests extends JCacheEhCacheApiTests {
|
||||
|
||||
@Override
|
||||
protected CachingProvider getCachingProvider() {
|
||||
return Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
|
||||
}
|
||||
|
||||
}
|
|
@ -64,7 +64,7 @@ public class JCacheEhCacheAnnotationTests extends AbstractCacheAnnotationTests {
|
|||
}
|
||||
|
||||
protected CachingProvider getCachingProvider() {
|
||||
return Caching.getCachingProvider("org.ehcache.jcache.JCacheCachingProvider");
|
||||
return Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -54,7 +54,7 @@ public class JCacheEhCacheApiTests extends AbstractValueAdaptingCacheTests<JCach
|
|||
}
|
||||
|
||||
protected CachingProvider getCachingProvider() {
|
||||
return Caching.getCachingProvider("org.ehcache.jcache.JCacheCachingProvider");
|
||||
return Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -24,18 +24,17 @@ import java.util.GregorianCalendar;
|
|||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.mail.Address;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.NoSuchProviderException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.URLName;
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import jakarta.activation.FileTypeMap;
|
||||
import jakarta.mail.Address;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.NoSuchProviderException;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Transport;
|
||||
import jakarta.mail.URLName;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mail.MailParseException;
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.validation.beanvalidation2;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.validation.beanvalidation.BeanValidationPostProcessor;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class BeanValidationPostProcessorTests {
|
||||
|
||||
@Test
|
||||
public void testNotNullConstraint() {
|
||||
GenericApplicationContext ac = new GenericApplicationContext();
|
||||
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
||||
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
||||
ac.registerBeanDefinition("bean", new RootBeanDefinition(NotNullConstrainedBean.class));
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(ac::refresh)
|
||||
.havingRootCause()
|
||||
.withMessageContainingAll("testBean", "invalid");
|
||||
ac.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotNullConstraintSatisfied() {
|
||||
GenericApplicationContext ac = new GenericApplicationContext();
|
||||
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
||||
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
||||
RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class);
|
||||
bd.getPropertyValues().add("testBean", new TestBean());
|
||||
ac.registerBeanDefinition("bean", bd);
|
||||
ac.refresh();
|
||||
ac.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotNullConstraintAfterInitialization() {
|
||||
GenericApplicationContext ac = new GenericApplicationContext();
|
||||
RootBeanDefinition bvpp = new RootBeanDefinition(BeanValidationPostProcessor.class);
|
||||
bvpp.getPropertyValues().add("afterInitialization", true);
|
||||
ac.registerBeanDefinition("bvpp", bvpp);
|
||||
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
||||
ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class));
|
||||
ac.refresh();
|
||||
ac.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSizeConstraint() {
|
||||
GenericApplicationContext ac = new GenericApplicationContext();
|
||||
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
||||
RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class);
|
||||
bd.getPropertyValues().add("testBean", new TestBean());
|
||||
bd.getPropertyValues().add("stringValue", "s");
|
||||
ac.registerBeanDefinition("bean", bd);
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(ac::refresh)
|
||||
.havingRootCause()
|
||||
.withMessageContainingAll("stringValue", "invalid");
|
||||
ac.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSizeConstraintSatisfied() {
|
||||
GenericApplicationContext ac = new GenericApplicationContext();
|
||||
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
||||
RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class);
|
||||
bd.getPropertyValues().add("testBean", new TestBean());
|
||||
bd.getPropertyValues().add("stringValue", "ss");
|
||||
ac.registerBeanDefinition("bean", bd);
|
||||
ac.refresh();
|
||||
ac.close();
|
||||
}
|
||||
|
||||
|
||||
public static class NotNullConstrainedBean {
|
||||
|
||||
@NotNull
|
||||
private TestBean testBean;
|
||||
|
||||
@Size(min = 2)
|
||||
private String stringValue;
|
||||
|
||||
public TestBean getTestBean() {
|
||||
return testBean;
|
||||
}
|
||||
|
||||
public void setTestBean(TestBean testBean) {
|
||||
this.testBean = testBean;
|
||||
}
|
||||
|
||||
public String getStringValue() {
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
public void setStringValue(String stringValue) {
|
||||
this.stringValue = stringValue;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
assertThat(this.testBean).as("Shouldn't be here after constraint checking").isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class AfterInitConstraintBean {
|
||||
|
||||
@NotNull
|
||||
private TestBean testBean;
|
||||
|
||||
public TestBean getTestBean() {
|
||||
return testBean;
|
||||
}
|
||||
|
||||
public void setTestBean(TestBean testBean) {
|
||||
this.testBean = testBean;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.testBean = new TestBean();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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.validation.beanvalidation2;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import javax.validation.ValidationException;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.groups.Default;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
|
||||
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.beanvalidation.CustomValidatorBean;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationInterceptor;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class MethodValidationTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testMethodValidationInterceptor() {
|
||||
MyValidBean bean = new MyValidBean();
|
||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||
proxyFactory.addAdvice(new MethodValidationInterceptor());
|
||||
proxyFactory.addAdvisor(new AsyncAnnotationAdvisor());
|
||||
doTestProxyValidation((MyValidInterface<String>) proxyFactory.getProxy());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testMethodValidationPostProcessor() {
|
||||
StaticApplicationContext ac = new StaticApplicationContext();
|
||||
ac.registerSingleton("mvpp", MethodValidationPostProcessor.class);
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("beforeExistingAdvisors", false);
|
||||
ac.registerSingleton("aapp", AsyncAnnotationBeanPostProcessor.class, pvs);
|
||||
ac.registerSingleton("bean", MyValidBean.class);
|
||||
ac.refresh();
|
||||
doTestProxyValidation(ac.getBean("bean", MyValidInterface.class));
|
||||
ac.close();
|
||||
}
|
||||
|
||||
private void doTestProxyValidation(MyValidInterface<String> proxy) {
|
||||
assertThat(proxy.myValidMethod("value", 5)).isNotNull();
|
||||
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
|
||||
proxy.myValidMethod("value", 15));
|
||||
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
|
||||
proxy.myValidMethod(null, 5));
|
||||
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
|
||||
proxy.myValidMethod("value", 0));
|
||||
proxy.myValidAsyncMethod("value", 5);
|
||||
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
|
||||
proxy.myValidAsyncMethod("value", 15));
|
||||
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
|
||||
proxy.myValidAsyncMethod(null, 5));
|
||||
assertThat(proxy.myGenericMethod("myValue")).isEqualTo("myValue");
|
||||
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
|
||||
proxy.myGenericMethod(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyValidatorForMethodValidation() {
|
||||
@SuppressWarnings("resource")
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
|
||||
LazyMethodValidationConfig.class, CustomValidatorBean.class,
|
||||
MyValidBean.class, MyValidFactoryBean.class);
|
||||
ctx.getBeansOfType(MyValidInterface.class).values().forEach(bean -> bean.myValidMethod("value", 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyValidatorForMethodValidationWithProxyTargetClass() {
|
||||
@SuppressWarnings("resource")
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
|
||||
LazyMethodValidationConfigWithProxyTargetClass.class, CustomValidatorBean.class,
|
||||
MyValidBean.class, MyValidFactoryBean.class);
|
||||
ctx.getBeansOfType(MyValidInterface.class).values().forEach(bean -> bean.myValidMethod("value", 5));
|
||||
}
|
||||
|
||||
|
||||
@MyStereotype
|
||||
public static class MyValidBean implements MyValidInterface<String> {
|
||||
|
||||
@Override
|
||||
public Object myValidMethod(String arg1, int arg2) {
|
||||
return (arg2 == 0 ? null : "value");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void myValidAsyncMethod(String arg1, int arg2) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String myGenericMethod(String value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@MyStereotype
|
||||
public static class MyValidFactoryBean implements FactoryBean<String>, MyValidInterface<String> {
|
||||
|
||||
@Override
|
||||
public String getObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object myValidMethod(String arg1, int arg2) {
|
||||
return (arg2 == 0 ? null : "value");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void myValidAsyncMethod(String arg1, int arg2) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String myGenericMethod(String value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface MyValidInterface<T> {
|
||||
|
||||
@NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2);
|
||||
|
||||
@MyValid
|
||||
@Async void myValidAsyncMethod(@NotNull(groups = OtherGroup.class) String arg1, @Max(10) int arg2);
|
||||
|
||||
T myGenericMethod(@NotNull T value);
|
||||
}
|
||||
|
||||
|
||||
public interface MyGroup {
|
||||
}
|
||||
|
||||
|
||||
public interface OtherGroup {
|
||||
}
|
||||
|
||||
|
||||
@Validated({MyGroup.class, Default.class})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MyStereotype {
|
||||
}
|
||||
|
||||
|
||||
@Validated({OtherGroup.class, Default.class})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MyValid {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
public static class LazyMethodValidationConfig {
|
||||
|
||||
@Bean
|
||||
public static MethodValidationPostProcessor methodValidationPostProcessor(@Lazy Validator validator) {
|
||||
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
|
||||
postProcessor.setValidator(validator);
|
||||
return postProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
public static class LazyMethodValidationConfigWithProxyTargetClass {
|
||||
|
||||
@Bean
|
||||
public static MethodValidationPostProcessor methodValidationPostProcessor(@Lazy Validator validator) {
|
||||
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
|
||||
postProcessor.setValidator(validator);
|
||||
postProcessor.setProxyTargetClass(true);
|
||||
return postProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,563 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.validation.beanvalidation2;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Payload;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.context.support.StaticMessageSource;
|
||||
import org.springframework.core.testfixture.io.SerializationTestUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Kazuki Shimizu
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class SpringValidatorAdapterTests {
|
||||
|
||||
private final Validator nativeValidator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
|
||||
private final SpringValidatorAdapter validatorAdapter = new SpringValidatorAdapter(nativeValidator);
|
||||
|
||||
private final StaticMessageSource messageSource = new StaticMessageSource();
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setupSpringValidatorAdapter() {
|
||||
messageSource.addMessage("Size", Locale.ENGLISH, "Size of {0} must be between {2} and {1}");
|
||||
messageSource.addMessage("Same", Locale.ENGLISH, "{2} must be same value as {1}");
|
||||
messageSource.addMessage("password", Locale.ENGLISH, "Password");
|
||||
messageSource.addMessage("confirmPassword", Locale.ENGLISH, "Password(Confirm)");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUnwrap() {
|
||||
Validator nativeValidator = validatorAdapter.unwrap(Validator.class);
|
||||
assertThat(nativeValidator).isSameAs(this.nativeValidator);
|
||||
}
|
||||
|
||||
@Test // SPR-13406
|
||||
public void testNoStringArgumentValue() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
testBean.setPassword("pass");
|
||||
testBean.setConfirmPassword("pass");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
|
||||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("password")).isEqualTo(1);
|
||||
assertThat(errors.getFieldValue("password")).isEqualTo("pass");
|
||||
FieldError error = errors.getFieldError("password");
|
||||
assertThat(error).isNotNull();
|
||||
assertThat(messageSource.getMessage(error, Locale.ENGLISH)).isEqualTo("Size of Password must be between 8 and 128");
|
||||
assertThat(error.contains(ConstraintViolation.class)).isTrue();
|
||||
assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("password");
|
||||
assertThat(SerializationTestUtils.serializeAndDeserialize(error.toString())).isEqualTo(error.toString());
|
||||
}
|
||||
|
||||
@Test // SPR-13406
|
||||
public void testApplyMessageSourceResolvableToStringArgumentValueWithResolvedLogicalFieldName() throws Exception {
|
||||
TestBean testBean = new TestBean();
|
||||
testBean.setPassword("password");
|
||||
testBean.setConfirmPassword("PASSWORD");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
|
||||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("password")).isEqualTo(1);
|
||||
assertThat(errors.getFieldValue("password")).isEqualTo("password");
|
||||
FieldError error = errors.getFieldError("password");
|
||||
assertThat(error).isNotNull();
|
||||
assertThat(messageSource.getMessage(error, Locale.ENGLISH)).isEqualTo("Password must be same value as Password(Confirm)");
|
||||
assertThat(error.contains(ConstraintViolation.class)).isTrue();
|
||||
assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("password");
|
||||
assertThat(SerializationTestUtils.serializeAndDeserialize(error.toString())).isEqualTo(error.toString());
|
||||
}
|
||||
|
||||
@Test // SPR-13406
|
||||
public void testApplyMessageSourceResolvableToStringArgumentValueWithUnresolvedLogicalFieldName() {
|
||||
TestBean testBean = new TestBean();
|
||||
testBean.setEmail("test@example.com");
|
||||
testBean.setConfirmEmail("TEST@EXAMPLE.IO");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
|
||||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("email")).isEqualTo(1);
|
||||
assertThat(errors.getFieldValue("email")).isEqualTo("test@example.com");
|
||||
assertThat(errors.getFieldErrorCount("confirmEmail")).isEqualTo(1);
|
||||
FieldError error1 = errors.getFieldError("email");
|
||||
FieldError error2 = errors.getFieldError("confirmEmail");
|
||||
assertThat(error1).isNotNull();
|
||||
assertThat(error2).isNotNull();
|
||||
assertThat(messageSource.getMessage(error1, Locale.ENGLISH)).isEqualTo("email must be same value as confirmEmail");
|
||||
assertThat(messageSource.getMessage(error2, Locale.ENGLISH)).isEqualTo("Email required");
|
||||
assertThat(error1.contains(ConstraintViolation.class)).isTrue();
|
||||
assertThat(error1.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("email");
|
||||
assertThat(error2.contains(ConstraintViolation.class)).isTrue();
|
||||
assertThat(error2.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("confirmEmail");
|
||||
}
|
||||
|
||||
@Test // SPR-15123
|
||||
public void testApplyMessageSourceResolvableToStringArgumentValueWithAlwaysUseMessageFormat() {
|
||||
messageSource.setAlwaysUseMessageFormat(true);
|
||||
|
||||
TestBean testBean = new TestBean();
|
||||
testBean.setEmail("test@example.com");
|
||||
testBean.setConfirmEmail("TEST@EXAMPLE.IO");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
|
||||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("email")).isEqualTo(1);
|
||||
assertThat(errors.getFieldValue("email")).isEqualTo("test@example.com");
|
||||
assertThat(errors.getFieldErrorCount("confirmEmail")).isEqualTo(1);
|
||||
FieldError error1 = errors.getFieldError("email");
|
||||
FieldError error2 = errors.getFieldError("confirmEmail");
|
||||
assertThat(error1).isNotNull();
|
||||
assertThat(error2).isNotNull();
|
||||
assertThat(messageSource.getMessage(error1, Locale.ENGLISH)).isEqualTo("email must be same value as confirmEmail");
|
||||
assertThat(messageSource.getMessage(error2, Locale.ENGLISH)).isEqualTo("Email required");
|
||||
assertThat(error1.contains(ConstraintViolation.class)).isTrue();
|
||||
assertThat(error1.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("email");
|
||||
assertThat(error2.contains(ConstraintViolation.class)).isTrue();
|
||||
assertThat(error2.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("confirmEmail");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatternMessage() {
|
||||
TestBean testBean = new TestBean();
|
||||
testBean.setEmail("X");
|
||||
testBean.setConfirmEmail("X");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
|
||||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("email")).isEqualTo(1);
|
||||
assertThat(errors.getFieldValue("email")).isEqualTo("X");
|
||||
FieldError error = errors.getFieldError("email");
|
||||
assertThat(error).isNotNull();
|
||||
assertThat(messageSource.getMessage(error, Locale.ENGLISH)).contains("[\\w.'-]{1,}@[\\w.'-]{1,}");
|
||||
assertThat(error.contains(ConstraintViolation.class)).isTrue();
|
||||
assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("email");
|
||||
}
|
||||
|
||||
@Test // SPR-16177
|
||||
public void testWithList() {
|
||||
Parent parent = new Parent();
|
||||
parent.setName("Parent whit list");
|
||||
parent.getChildList().addAll(createChildren(parent));
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(parent, "parent");
|
||||
validatorAdapter.validate(parent, errors);
|
||||
|
||||
assertThat(errors.getErrorCount() > 0).isTrue();
|
||||
}
|
||||
|
||||
@Test // SPR-16177
|
||||
public void testWithSet() {
|
||||
Parent parent = new Parent();
|
||||
parent.setName("Parent with set");
|
||||
parent.getChildSet().addAll(createChildren(parent));
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(parent, "parent");
|
||||
validatorAdapter.validate(parent, errors);
|
||||
|
||||
assertThat(errors.getErrorCount() > 0).isTrue();
|
||||
}
|
||||
|
||||
private List<Child> createChildren(Parent parent) {
|
||||
Child child1 = new Child();
|
||||
child1.setName("Child1");
|
||||
child1.setAge(null);
|
||||
child1.setParent(parent);
|
||||
|
||||
Child child2 = new Child();
|
||||
child2.setName(null);
|
||||
child2.setAge(17);
|
||||
child2.setParent(parent);
|
||||
|
||||
return Arrays.asList(child1, child2);
|
||||
}
|
||||
|
||||
@Test // SPR-15839
|
||||
public void testListElementConstraint() {
|
||||
BeanWithListElementConstraint bean = new BeanWithListElementConstraint();
|
||||
bean.setProperty(Arrays.asList("no", "element", "can", "be", null));
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(bean, "bean");
|
||||
validatorAdapter.validate(bean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("property[4]")).isEqualTo(1);
|
||||
assertThat(errors.getFieldValue("property[4]")).isNull();
|
||||
}
|
||||
|
||||
@Test // SPR-15839
|
||||
public void testMapValueConstraint() {
|
||||
Map<String, String> property = new HashMap<>();
|
||||
property.put("no value can be", null);
|
||||
|
||||
BeanWithMapEntryConstraint bean = new BeanWithMapEntryConstraint();
|
||||
bean.setProperty(property);
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(bean, "bean");
|
||||
validatorAdapter.validate(bean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("property[no value can be]")).isEqualTo(1);
|
||||
assertThat(errors.getFieldValue("property[no value can be]")).isNull();
|
||||
}
|
||||
|
||||
@Test // SPR-15839
|
||||
public void testMapEntryConstraint() {
|
||||
Map<String, String> property = new HashMap<>();
|
||||
property.put(null, null);
|
||||
|
||||
BeanWithMapEntryConstraint bean = new BeanWithMapEntryConstraint();
|
||||
bean.setProperty(property);
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(bean, "bean");
|
||||
validatorAdapter.validate(bean, errors);
|
||||
|
||||
assertThat(errors.hasFieldErrors("property[]")).isTrue();
|
||||
assertThat(errors.getFieldValue("property[]")).isNull();
|
||||
}
|
||||
|
||||
|
||||
@Same(field = "password", comparingField = "confirmPassword")
|
||||
@Same(field = "email", comparingField = "confirmEmail")
|
||||
static class TestBean {
|
||||
|
||||
@Size(min = 8, max = 128)
|
||||
private String password;
|
||||
|
||||
private String confirmPassword;
|
||||
|
||||
@Pattern(regexp = "[\\w.'-]{1,}@[\\w.'-]{1,}")
|
||||
private String email;
|
||||
|
||||
@Pattern(regexp = "[\\p{L} -]*", message = "Email required")
|
||||
private String confirmEmail;
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getConfirmPassword() {
|
||||
return confirmPassword;
|
||||
}
|
||||
|
||||
public void setConfirmPassword(String confirmPassword) {
|
||||
this.confirmPassword = confirmPassword;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getConfirmEmail() {
|
||||
return confirmEmail;
|
||||
}
|
||||
|
||||
public void setConfirmEmail(String confirmEmail) {
|
||||
this.confirmEmail = confirmEmail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Documented
|
||||
@Constraint(validatedBy = {SameValidator.class})
|
||||
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(SameGroup.class)
|
||||
@interface Same {
|
||||
|
||||
String message() default "{org.springframework.validation.beanvalidation.Same.message}";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
String field();
|
||||
|
||||
String comparingField();
|
||||
|
||||
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@interface List {
|
||||
Same[] value();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Documented
|
||||
@Inherited
|
||||
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface SameGroup {
|
||||
|
||||
Same[] value();
|
||||
}
|
||||
|
||||
|
||||
public static class SameValidator implements ConstraintValidator<Same, Object> {
|
||||
|
||||
private String field;
|
||||
|
||||
private String comparingField;
|
||||
|
||||
private String message;
|
||||
|
||||
@Override
|
||||
public void initialize(Same constraintAnnotation) {
|
||||
field = constraintAnnotation.field();
|
||||
comparingField = constraintAnnotation.comparingField();
|
||||
message = constraintAnnotation.message();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||
BeanWrapper beanWrapper = new BeanWrapperImpl(value);
|
||||
Object fieldValue = beanWrapper.getPropertyValue(field);
|
||||
Object comparingFieldValue = beanWrapper.getPropertyValue(comparingField);
|
||||
boolean matched = ObjectUtils.nullSafeEquals(fieldValue, comparingFieldValue);
|
||||
if (matched) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
context.disableDefaultConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate(message)
|
||||
.addPropertyNode(field)
|
||||
.addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Parent {
|
||||
|
||||
private Integer id;
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@Valid
|
||||
private Set<Child> childSet = new LinkedHashSet<>();
|
||||
|
||||
@Valid
|
||||
private List<Child> childList = new ArrayList<>();
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Set<Child> getChildSet() {
|
||||
return childSet;
|
||||
}
|
||||
|
||||
public void setChildSet(Set<Child> childSet) {
|
||||
this.childSet = childSet;
|
||||
}
|
||||
|
||||
public List<Child> getChildList() {
|
||||
return childList;
|
||||
}
|
||||
|
||||
public void setChildList(List<Child> childList) {
|
||||
this.childList = childList;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AnythingValid
|
||||
public static class Child {
|
||||
|
||||
private Integer id;
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@NotNull
|
||||
private Integer age;
|
||||
|
||||
@NotNull
|
||||
private Parent parent;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public Parent getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(Parent parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Constraint(validatedBy = AnythingValidator.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnythingValid {
|
||||
|
||||
String message() default "{AnythingValid.message}";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
|
||||
|
||||
public static class AnythingValidator implements ConstraintValidator<AnythingValid, Object> {
|
||||
|
||||
private static final String ID = "id";
|
||||
|
||||
@Override
|
||||
public void initialize(AnythingValid constraintAnnotation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||
List<Field> fieldsErrors = new ArrayList<>();
|
||||
Arrays.asList(value.getClass().getDeclaredFields()).forEach(field -> {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
if (!field.getName().equals(ID) && field.get(value) == null) {
|
||||
fieldsErrors.add(field);
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
|
||||
.addPropertyNode(field.getName())
|
||||
.addConstraintViolation();
|
||||
}
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
});
|
||||
return fieldsErrors.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class BeanWithListElementConstraint {
|
||||
|
||||
@Valid
|
||||
private List<@NotNull String> property;
|
||||
|
||||
public List<String> getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(List<String> property) {
|
||||
this.property = property;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class BeanWithMapEntryConstraint {
|
||||
|
||||
@Valid
|
||||
private Map<@NotNull String, @NotNull String> property;
|
||||
|
||||
public Map<String, String> getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(Map<String, String> property) {
|
||||
this.property = property;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,505 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.validation.beanvalidation2;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Payload;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
import org.hibernate.validator.HibernateValidatorFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public class ValidatorFactoryTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("cast")
|
||||
public void testSimpleValidation() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
||||
assertThat(result.size()).isEqualTo(2);
|
||||
for (ConstraintViolation<ValidPerson> cv : result) {
|
||||
String path = cv.getPropertyPath().toString();
|
||||
assertThat(path).matches(actual -> "name".equals(actual) || "address.street".equals(actual));
|
||||
assertThat(cv.getConstraintDescriptor().getAnnotation()).isInstanceOf(NotNull.class);
|
||||
}
|
||||
|
||||
Validator nativeValidator = validator.unwrap(Validator.class);
|
||||
assertThat(nativeValidator.getClass().getName().startsWith("org.hibernate")).isTrue();
|
||||
assertThat(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
|
||||
assertThat(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("cast")
|
||||
public void testSimpleValidationWithCustomProvider() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.setProviderClass(HibernateValidator.class);
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
||||
assertThat(result.size()).isEqualTo(2);
|
||||
for (ConstraintViolation<ValidPerson> cv : result) {
|
||||
String path = cv.getPropertyPath().toString();
|
||||
assertThat(path).matches(actual -> "name".equals(actual) || "address.street".equals(actual));
|
||||
assertThat(cv.getConstraintDescriptor().getAnnotation()).isInstanceOf(NotNull.class);
|
||||
}
|
||||
|
||||
Validator nativeValidator = validator.unwrap(Validator.class);
|
||||
assertThat(nativeValidator.getClass().getName().startsWith("org.hibernate")).isTrue();
|
||||
assertThat(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
|
||||
assertThat(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleValidationWithClassLevel() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
person.setName("Juergen");
|
||||
person.getAddress().setStreet("Juergen's Street");
|
||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
||||
assertThat(result.size()).isEqualTo(1);
|
||||
Iterator<ConstraintViolation<ValidPerson>> iterator = result.iterator();
|
||||
ConstraintViolation<?> cv = iterator.next();
|
||||
assertThat(cv.getPropertyPath().toString()).isEqualTo("");
|
||||
assertThat(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationFieldType() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
person.setName("Phil");
|
||||
person.getAddress().setStreet("Phil's Street");
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(person, "person");
|
||||
validator.validate(person, errors);
|
||||
assertThat(errors.getErrorCount()).isEqualTo(1);
|
||||
assertThat(errors.getFieldError("address").getRejectedValue()).isInstanceOf(ValidAddress.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidation() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
||||
validator.validate(person, result);
|
||||
assertThat(result.getErrorCount()).isEqualTo(2);
|
||||
FieldError fieldError = result.getFieldError("name");
|
||||
assertThat(fieldError.getField()).isEqualTo("name");
|
||||
List<String> errorCodes = Arrays.asList(fieldError.getCodes());
|
||||
assertThat(errorCodes.size()).isEqualTo(4);
|
||||
assertThat(errorCodes.contains("NotNull.person.name")).isTrue();
|
||||
assertThat(errorCodes.contains("NotNull.name")).isTrue();
|
||||
assertThat(errorCodes.contains("NotNull.java.lang.String")).isTrue();
|
||||
assertThat(errorCodes.contains("NotNull")).isTrue();
|
||||
fieldError = result.getFieldError("address.street");
|
||||
assertThat(fieldError.getField()).isEqualTo("address.street");
|
||||
errorCodes = Arrays.asList(fieldError.getCodes());
|
||||
assertThat(errorCodes.size()).isEqualTo(5);
|
||||
assertThat(errorCodes.contains("NotNull.person.address.street")).isTrue();
|
||||
assertThat(errorCodes.contains("NotNull.address.street")).isTrue();
|
||||
assertThat(errorCodes.contains("NotNull.street")).isTrue();
|
||||
assertThat(errorCodes.contains("NotNull.java.lang.String")).isTrue();
|
||||
assertThat(errorCodes.contains("NotNull")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationWithClassLevel() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
person.setName("Juergen");
|
||||
person.getAddress().setStreet("Juergen's Street");
|
||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
||||
validator.validate(person, result);
|
||||
assertThat(result.getErrorCount()).isEqualTo(1);
|
||||
ObjectError globalError = result.getGlobalError();
|
||||
List<String> errorCodes = Arrays.asList(globalError.getCodes());
|
||||
assertThat(errorCodes.size()).isEqualTo(2);
|
||||
assertThat(errorCodes.contains("NameAddressValid.person")).isTrue();
|
||||
assertThat(errorCodes.contains("NameAddressValid")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationWithAutowiredValidator() {
|
||||
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(
|
||||
LocalValidatorFactoryBean.class);
|
||||
LocalValidatorFactoryBean validator = ctx.getBean(LocalValidatorFactoryBean.class);
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
person.expectsAutowiredValidator = true;
|
||||
person.setName("Juergen");
|
||||
person.getAddress().setStreet("Juergen's Street");
|
||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
||||
validator.validate(person, result);
|
||||
assertThat(result.getErrorCount()).isEqualTo(1);
|
||||
ObjectError globalError = result.getGlobalError();
|
||||
List<String> errorCodes = Arrays.asList(globalError.getCodes());
|
||||
assertThat(errorCodes.size()).isEqualTo(2);
|
||||
assertThat(errorCodes.contains("NameAddressValid.person")).isTrue();
|
||||
assertThat(errorCodes.contains("NameAddressValid")).isTrue();
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationWithErrorInListElement() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
person.getAddressList().add(new ValidAddress());
|
||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
||||
validator.validate(person, result);
|
||||
assertThat(result.getErrorCount()).isEqualTo(3);
|
||||
FieldError fieldError = result.getFieldError("name");
|
||||
assertThat(fieldError.getField()).isEqualTo("name");
|
||||
fieldError = result.getFieldError("address.street");
|
||||
assertThat(fieldError.getField()).isEqualTo("address.street");
|
||||
fieldError = result.getFieldError("addressList[0].street");
|
||||
assertThat(fieldError.getField()).isEqualTo("addressList[0].street");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationWithErrorInSetElement() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
person.getAddressSet().add(new ValidAddress());
|
||||
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
|
||||
validator.validate(person, result);
|
||||
assertThat(result.getErrorCount()).isEqualTo(3);
|
||||
FieldError fieldError = result.getFieldError("name");
|
||||
assertThat(fieldError.getField()).isEqualTo("name");
|
||||
fieldError = result.getFieldError("address.street");
|
||||
assertThat(fieldError.getField()).isEqualTo("address.street");
|
||||
fieldError = result.getFieldError("addressSet[].street");
|
||||
assertThat(fieldError.getField()).isEqualTo("addressSet[].street");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInnerBeanValidation() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
MainBean mainBean = new MainBean();
|
||||
Errors errors = new BeanPropertyBindingResult(mainBean, "mainBean");
|
||||
validator.validate(mainBean, errors);
|
||||
Object rejected = errors.getFieldValue("inner.value");
|
||||
assertThat(rejected).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidationWithOptionalField() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
MainBeanWithOptional mainBean = new MainBeanWithOptional();
|
||||
Errors errors = new BeanPropertyBindingResult(mainBean, "mainBean");
|
||||
validator.validate(mainBean, errors);
|
||||
Object rejected = errors.getFieldValue("inner.value");
|
||||
assertThat(rejected).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListValidation() {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ListContainer listContainer = new ListContainer();
|
||||
listContainer.addString("A");
|
||||
listContainer.addString("X");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(listContainer, "listContainer");
|
||||
errors.initConversion(new DefaultConversionService());
|
||||
validator.validate(listContainer, errors);
|
||||
|
||||
FieldError fieldError = errors.getFieldError("list[1]");
|
||||
assertThat(fieldError).isNotNull();
|
||||
assertThat(fieldError.getRejectedValue()).isEqualTo("X");
|
||||
assertThat(errors.getFieldValue("list[1]")).isEqualTo("X");
|
||||
}
|
||||
|
||||
|
||||
@NameAddressValid
|
||||
public static class ValidPerson {
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@Valid
|
||||
private ValidAddress address = new ValidAddress();
|
||||
|
||||
@Valid
|
||||
private List<ValidAddress> addressList = new ArrayList<>();
|
||||
|
||||
@Valid
|
||||
private Set<ValidAddress> addressSet = new LinkedHashSet<>();
|
||||
|
||||
public boolean expectsAutowiredValidator = false;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ValidAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(ValidAddress address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public List<ValidAddress> getAddressList() {
|
||||
return addressList;
|
||||
}
|
||||
|
||||
public void setAddressList(List<ValidAddress> addressList) {
|
||||
this.addressList = addressList;
|
||||
}
|
||||
|
||||
public Set<ValidAddress> getAddressSet() {
|
||||
return addressSet;
|
||||
}
|
||||
|
||||
public void setAddressSet(Set<ValidAddress> addressSet) {
|
||||
this.addressSet = addressSet;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ValidAddress {
|
||||
|
||||
@NotNull
|
||||
private String street;
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = NameAddressValidator.class)
|
||||
public @interface NameAddressValid {
|
||||
|
||||
String message() default "Street must not contain name";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<?>[] payload() default {};
|
||||
}
|
||||
|
||||
|
||||
public static class NameAddressValidator implements ConstraintValidator<NameAddressValid, ValidPerson> {
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
public void initialize(NameAddressValid constraintAnnotation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(ValidPerson value, ConstraintValidatorContext context) {
|
||||
if (value.expectsAutowiredValidator) {
|
||||
assertThat(this.environment).isNotNull();
|
||||
}
|
||||
boolean valid = (value.name == null || !value.address.street.contains(value.name));
|
||||
if (!valid && "Phil".equals(value.name)) {
|
||||
context.buildConstraintViolationWithTemplate(
|
||||
context.getDefaultConstraintMessageTemplate()).addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class MainBean {
|
||||
|
||||
@InnerValid
|
||||
private InnerBean inner = new InnerBean();
|
||||
|
||||
public InnerBean getInner() {
|
||||
return inner;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class MainBeanWithOptional {
|
||||
|
||||
@InnerValid
|
||||
private InnerBean inner = new InnerBean();
|
||||
|
||||
public Optional<InnerBean> getInner() {
|
||||
return Optional.ofNullable(inner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class InnerBean {
|
||||
|
||||
private String value;
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Constraint(validatedBy=InnerValidator.class)
|
||||
public static @interface InnerValid {
|
||||
|
||||
String message() default "NOT VALID";
|
||||
|
||||
Class<?>[] groups() default { };
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
|
||||
|
||||
public static class InnerValidator implements ConstraintValidator<InnerValid, InnerBean> {
|
||||
|
||||
@Override
|
||||
public void initialize(InnerValid constraintAnnotation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
if (bean.getValue() == null) {
|
||||
context.buildConstraintViolationWithTemplate("NULL").addPropertyNode("value").addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ListContainer {
|
||||
|
||||
@NotXList
|
||||
private List<String> list = new ArrayList<>();
|
||||
|
||||
public void addString(String value) {
|
||||
list.add(value);
|
||||
}
|
||||
|
||||
public List<String> getList() {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Constraint(validatedBy = NotXListValidator.class)
|
||||
public @interface NotXList {
|
||||
|
||||
String message() default "Should not be X";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
|
||||
|
||||
public static class NotXListValidator implements ConstraintValidator<NotXList, List<String>> {
|
||||
|
||||
@Override
|
||||
public void initialize(NotXList constraintAnnotation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(List<String> list, ConstraintValidatorContext context) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if ("X".equals(list.get(i))) {
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addBeanNode().inIterable().atIndex(i).addConstraintViolation();
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -9,20 +9,18 @@ dependencies {
|
|||
api(project(":spring-core"))
|
||||
api(project(":spring-expression"))
|
||||
optional(project(":spring-instrument"))
|
||||
optional("javax.annotation:javax.annotation-api")
|
||||
optional("javax.ejb:javax.ejb-api")
|
||||
optional("javax.enterprise.concurrent:javax.enterprise.concurrent-api")
|
||||
optional("javax.inject:javax.inject")
|
||||
optional("javax.interceptor:javax.interceptor-api")
|
||||
optional("jakarta.annotation:jakarta.annotation-api")
|
||||
optional("jakarta.ejb:jakarta.ejb-api")
|
||||
optional("jakarta.enterprise.concurrent:jakarta.enterprise.concurrent-api")
|
||||
optional("jakarta.inject:jakarta.inject-api")
|
||||
optional("jakarta.interceptor:jakarta.interceptor-api")
|
||||
optional("javax.money:money-api")
|
||||
// Overriding 2.0.1.Final due to Bean Validation 1.1 compatibility in LocalValidatorFactoryBean
|
||||
optional("javax.validation:validation-api:1.1.0.Final")
|
||||
optional("javax.xml.ws:jaxws-api")
|
||||
optional("jakarta.validation:jakarta.validation-api")
|
||||
optional("jakarta.xml.ws:jakarta.xml.ws-api")
|
||||
optional("org.aspectj:aspectjweaver")
|
||||
optional("org.codehaus.groovy:groovy")
|
||||
optional("org.apache-extras.beanshell:bsh")
|
||||
optional("joda-time:joda-time")
|
||||
optional("org.hibernate:hibernate-validator:5.4.3.Final")
|
||||
optional("org.hibernate:hibernate-validator")
|
||||
optional("org.jetbrains.kotlin:kotlin-reflect")
|
||||
optional("org.jetbrains.kotlin:kotlin-stdlib")
|
||||
optional("org.reactivestreams:reactive-streams")
|
||||
|
@ -34,10 +32,10 @@ dependencies {
|
|||
testImplementation("org.codehaus.groovy:groovy-test")
|
||||
testImplementation("org.codehaus.groovy:groovy-xml")
|
||||
testImplementation("org.apache.commons:commons-pool2")
|
||||
testImplementation("javax.inject:javax.inject-tck")
|
||||
testImplementation("jakarta.inject:jakarta.inject-tck")
|
||||
testImplementation("org.awaitility:awaitility")
|
||||
testRuntimeOnly("javax.xml.bind:jaxb-api")
|
||||
testRuntimeOnly("org.glassfish:javax.el")
|
||||
testRuntimeOnly("jakarta.xml.bind:jakarta.xml.bind-api")
|
||||
testRuntimeOnly("org.glassfish:jakarta.el")
|
||||
// Substitute for javax.management:jmxremote_optional:1.0.1_04 (not available on Maven Central)
|
||||
testRuntimeOnly("org.glassfish.external:opendmk_jmxremote_optional_jar")
|
||||
testRuntimeOnly("org.javamoney:moneta")
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
|
|
|
@ -41,8 +41,8 @@ import org.springframework.util.StringUtils;
|
|||
* {@link org.springframework.stereotype.Repository @Repository}) are
|
||||
* themselves annotated with {@code @Component}.
|
||||
*
|
||||
* <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
|
||||
* JSR-330's {@link javax.inject.Named} annotations, if available. Note that
|
||||
* <p>Also supports Jakarta EE's {@link jakarta.annotation.ManagedBean} and
|
||||
* JSR-330's {@link jakarta.inject.Named} annotations, if available. Note that
|
||||
* Spring component annotations always override such standard annotations.
|
||||
*
|
||||
* <p>If the annotation's value doesn't indicate a bean name, an appropriate
|
||||
|
@ -58,7 +58,7 @@ import org.springframework.util.StringUtils;
|
|||
* @see org.springframework.stereotype.Repository#value()
|
||||
* @see org.springframework.stereotype.Service#value()
|
||||
* @see org.springframework.stereotype.Controller#value()
|
||||
* @see javax.inject.Named#value()
|
||||
* @see jakarta.inject.Named#value()
|
||||
* @see FullyQualifiedAnnotationBeanNameGenerator
|
||||
*/
|
||||
public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
|
@ -136,8 +136,8 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
|||
|
||||
boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
|
||||
metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME) ||
|
||||
annotationType.equals("javax.annotation.ManagedBean") ||
|
||||
annotationType.equals("javax.inject.Named");
|
||||
annotationType.equals("jakarta.annotation.ManagedBean") ||
|
||||
annotationType.equals("jakarta.inject.Named");
|
||||
|
||||
return (isStereotype && attributes != null && attributes.containsKey("value"));
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.springframework.util.Assert;
|
|||
* Standalone application context, accepting <em>component classes</em> as input —
|
||||
* in particular {@link Configuration @Configuration}-annotated classes, but also plain
|
||||
* {@link org.springframework.stereotype.Component @Component} types and JSR-330 compliant
|
||||
* classes using {@code javax.inject} annotations.
|
||||
* classes using {@code jakarta.inject} annotations.
|
||||
*
|
||||
* <p>Allows for registering classes one by one using {@link #register(Class...)}
|
||||
* as well as for classpath scanning using {@link #scan(String...)}.
|
||||
|
|
|
@ -123,8 +123,8 @@ public abstract class AnnotationConfigUtils {
|
|||
|
||||
static {
|
||||
ClassLoader classLoader = AnnotationConfigUtils.class.getClassLoader();
|
||||
jsr250Present = ClassUtils.isPresent("javax.annotation.Resource", classLoader);
|
||||
jpaPresent = ClassUtils.isPresent("javax.persistence.EntityManagerFactory", classLoader) &&
|
||||
jsr250Present = ClassUtils.isPresent("jakarta.annotation.Resource", classLoader);
|
||||
jpaPresent = ClassUtils.isPresent("jakarta.persistence.EntityManagerFactory", classLoader) &&
|
||||
ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, classLoader);
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ import org.springframework.core.annotation.AliasFor;
|
|||
* <p><b>NOTE:</b> {@code @Order} values may influence priorities at injection points,
|
||||
* but please be aware that they do not influence singleton startup order which is an
|
||||
* orthogonal concern determined by dependency relationships and {@code @DependsOn}
|
||||
* declarations as mentioned above. Also, {@link javax.annotation.Priority} is not
|
||||
* declarations as mentioned above. Also, {@link jakarta.annotation.Priority} is not
|
||||
* available at this level since it cannot be declared on methods; its semantics can
|
||||
* be modeled through {@code @Order} values in combination with {@code @Primary} on
|
||||
* a single bean per type.
|
||||
|
|
|
@ -47,8 +47,8 @@ import org.springframework.util.PatternMatchUtils;
|
|||
* {@link org.springframework.stereotype.Service @Service}, or
|
||||
* {@link org.springframework.stereotype.Controller @Controller} stereotype.
|
||||
*
|
||||
* <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
|
||||
* JSR-330's {@link javax.inject.Named} annotations, if available.
|
||||
* <p>Also supports Jakarta EE's {@link jakarta.annotation.ManagedBean} and
|
||||
* JSR-330's {@link jakarta.inject.Named} annotations, if available.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
|
|
|
@ -197,8 +197,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
|||
* {@link Component @Component} meta-annotation including the
|
||||
* {@link Repository @Repository}, {@link Service @Service}, and
|
||||
* {@link Controller @Controller} stereotype annotations.
|
||||
* <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
|
||||
* JSR-330's {@link javax.inject.Named} annotations, if available.
|
||||
* <p>Also supports Jakarta EE's {@link jakarta.annotation.ManagedBean} and
|
||||
* JSR-330's {@link jakarta.inject.Named} annotations, if available.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -207,16 +207,16 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
|||
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
|
||||
try {
|
||||
this.includeFilters.add(new AnnotationTypeFilter(
|
||||
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
|
||||
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
|
||||
((Class<? extends Annotation>) 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 Java EE 6) not available - simply skip.
|
||||
// JSR-250 1.1 API (as included in Jakarta EE) not available - simply skip.
|
||||
}
|
||||
try {
|
||||
this.includeFilters.add(new AnnotationTypeFilter(
|
||||
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
|
||||
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
|
||||
((Class<? extends Annotation>) ClassUtils.forName("jakarta.inject.Named", cl)), false));
|
||||
logger.trace("JSR-330 'jakarta.inject.Named' annotation found and supported for component scanning");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - simply skip.
|
||||
|
|
|
@ -37,14 +37,15 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.annotation.Resource;
|
||||
import javax.ejb.EJB;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.ws.Service;
|
||||
import javax.xml.ws.WebServiceClient;
|
||||
import javax.xml.ws.WebServiceRef;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.ejb.EJB;
|
||||
import jakarta.xml.ws.Service;
|
||||
import jakarta.xml.ws.WebServiceClient;
|
||||
import jakarta.xml.ws.WebServiceRef;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
|
@ -77,36 +78,32 @@ import org.springframework.util.StringValueResolver;
|
|||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
|
||||
* that supports common Java annotations out of the box, in particular the JSR-250
|
||||
* annotations in the {@code javax.annotation} package. These common Java
|
||||
* annotations are supported in many Java EE 5 technologies (e.g. JSF 1.2),
|
||||
* annotations in the {@code jakarta.annotation} package. These common Java
|
||||
* annotations are supported in many Jakarta EE technologies (e.g. JSF 1.2),
|
||||
* as well as in Java 6's JAX-WS.
|
||||
*
|
||||
* <p>This post-processor includes support for the {@link javax.annotation.PostConstruct}
|
||||
* and {@link javax.annotation.PreDestroy} annotations - as init annotation
|
||||
* <p>This post-processor includes support for the {@link jakarta.annotation.PostConstruct}
|
||||
* and {@link jakarta.annotation.PreDestroy} annotations - as init annotation
|
||||
* and destroy annotation, respectively - through inheriting from
|
||||
* {@link InitDestroyAnnotationBeanPostProcessor} with pre-configured annotation types.
|
||||
*
|
||||
* <p>The central element is the {@link javax.annotation.Resource} annotation
|
||||
* <p>The central element is the {@link jakarta.annotation.Resource} annotation
|
||||
* for annotation-driven injection of named beans, by default from the containing
|
||||
* Spring BeanFactory, with only {@code mappedName} references resolved in JNDI.
|
||||
* The {@link #setAlwaysUseJndiLookup "alwaysUseJndiLookup" flag} enforces JNDI lookups
|
||||
* equivalent to standard Java EE 5 resource injection for {@code name} references
|
||||
* equivalent to standard Jakarta EE resource injection for {@code name} references
|
||||
* and default names as well. The target beans can be simple POJOs, with no special
|
||||
* requirements other than the type having to match.
|
||||
*
|
||||
* <p>The JAX-WS {@link javax.xml.ws.WebServiceRef} annotation is supported too,
|
||||
* analogous to {@link javax.annotation.Resource} but with the capability of creating
|
||||
* analogous to {@link jakarta.annotation.Resource} but with the capability of creating
|
||||
* specific JAX-WS service endpoints. This may either point to an explicitly defined
|
||||
* resource by name or operate on a locally specified JAX-WS service class. Finally,
|
||||
* this post-processor also supports the EJB 3 {@link javax.ejb.EJB} annotation,
|
||||
* analogous to {@link javax.annotation.Resource} as well, with the capability to
|
||||
* this post-processor also supports the EJB 3 {@link jakarta.ejb.EJB} annotation,
|
||||
* analogous to {@link jakarta.annotation.Resource} as well, with the capability to
|
||||
* specify both a local bean name and a global JNDI name for fallback retrieval.
|
||||
* The target beans can be plain POJOs as well as EJB 3 Session Beans in this case.
|
||||
*
|
||||
* <p>The common annotations supported by this post-processor are available in
|
||||
* Java 6 (JDK 1.6) as well as in Java EE 5/6 (which provides a standalone jar for
|
||||
* its common annotations as well, allowing for use in any Java 5 based application).
|
||||
*
|
||||
* <p>For default usage, resolving resource names as Spring bean names,
|
||||
* simply define the following in your application context:
|
||||
*
|
||||
|
@ -114,7 +111,7 @@ import org.springframework.util.StringValueResolver;
|
|||
* <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/></pre>
|
||||
*
|
||||
* For direct JNDI access, resolving resource names as JNDI resource references
|
||||
* within the Java EE application's "java:comp/env/" namespace, use the following:
|
||||
* within the Jakarta EE application's "java:comp/env/" namespace, use the following:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
|
||||
|
@ -156,7 +153,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
|||
|
||||
static {
|
||||
webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
|
||||
ejbClass = loadAnnotationType("javax.ejb.EJB");
|
||||
ejbClass = loadAnnotationType("jakarta.ejb.EJB");
|
||||
|
||||
resourceAnnotationTypes.add(Resource.class);
|
||||
if (webServiceRefClass != null) {
|
||||
|
@ -191,7 +188,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
|||
/**
|
||||
* Create a new CommonAnnotationBeanPostProcessor,
|
||||
* with the init and destroy annotation types set to
|
||||
* {@link javax.annotation.PostConstruct} and {@link javax.annotation.PreDestroy},
|
||||
* {@link jakarta.annotation.PostConstruct} and {@link jakarta.annotation.PreDestroy},
|
||||
* respectively.
|
||||
*/
|
||||
public CommonAnnotationBeanPostProcessor() {
|
||||
|
@ -229,11 +226,11 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
|||
}
|
||||
|
||||
/**
|
||||
* Set whether to always use JNDI lookups equivalent to standard Java EE 5 resource
|
||||
* Set whether to always use JNDI lookups equivalent to standard Jakarta EE resource
|
||||
* injection, <b>even for {@code name} attributes and default names</b>.
|
||||
* <p>Default is "false": Resource names are used for Spring bean lookups in the
|
||||
* containing BeanFactory; only {@code mappedName} attributes point directly
|
||||
* into JNDI. Switch this flag to "true" for enforcing Java EE style JNDI lookups
|
||||
* into JNDI. Switch this flag to "true" for enforcing Jakarta EE style JNDI lookups
|
||||
* in any case, even for {@code name} attributes and default names.
|
||||
* @see #setJndiFactory
|
||||
* @see #setResourceFactory
|
||||
|
@ -249,7 +246,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
|||
* This factory will also be used if "alwaysUseJndiLookup" is set to "true" in order
|
||||
* to enforce JNDI lookups even for {@code name} attributes and default names.
|
||||
* <p>The default is a {@link org.springframework.jndi.support.SimpleJndiBeanFactory}
|
||||
* for JNDI lookup behavior equivalent to standard Java EE 5 resource injection.
|
||||
* for JNDI lookup behavior equivalent to standard Jakarta EE resource injection.
|
||||
* @see #setResourceFactory
|
||||
* @see #setAlwaysUseJndiLookup
|
||||
*/
|
||||
|
@ -266,7 +263,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
|||
* if any, looking up resource names as Spring bean names. Specify the resource
|
||||
* factory explicitly for programmatic usage of this post-processor.
|
||||
* <p>Specifying Spring's {@link org.springframework.jndi.support.SimpleJndiBeanFactory}
|
||||
* leads to JNDI lookup behavior equivalent to standard Java EE 5 resource injection,
|
||||
* leads to JNDI lookup behavior equivalent to standard Jakarta EE resource injection,
|
||||
* even for {@code name} attributes and default names. This is the same behavior
|
||||
* that the "alwaysUseJndiLookup" flag enables.
|
||||
* @see #setAlwaysUseJndiLookup
|
||||
|
|
|
@ -86,7 +86,7 @@ import org.springframework.stereotype.Component;
|
|||
* <p>{@code @Configuration} is meta-annotated with {@link Component @Component}, therefore
|
||||
* {@code @Configuration} classes are candidates for component scanning (typically using
|
||||
* Spring XML's {@code <context:component-scan/>} element) and therefore may also take
|
||||
* advantage of {@link Autowired @Autowired}/{@link javax.inject.Inject @Inject}
|
||||
* advantage of {@link Autowired @Autowired}/{@link jakarta.inject.Inject @Inject}
|
||||
* like any regular {@code @Component}. In particular, if a single constructor is present
|
||||
* autowiring semantics will be applied transparently for that constructor:
|
||||
*
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.springframework.lang.Nullable;
|
|||
|
||||
/**
|
||||
* Simple {@link ScopeMetadataResolver} implementation that follows JSR-330 scoping rules:
|
||||
* defaulting to prototype scope unless {@link javax.inject.Singleton} is present.
|
||||
* defaulting to prototype scope unless {@link jakarta.inject.Singleton} is present.
|
||||
*
|
||||
* <p>This scope resolver can be used with {@link ClassPathBeanDefinitionScanner} and
|
||||
* {@link AnnotatedBeanDefinitionReader} for standard JSR-330 compliance. However,
|
||||
|
@ -46,7 +46,7 @@ public class Jsr330ScopeMetadataResolver implements ScopeMetadataResolver {
|
|||
|
||||
|
||||
public Jsr330ScopeMetadataResolver() {
|
||||
registerScope("javax.inject.Singleton", BeanDefinition.SCOPE_SINGLETON);
|
||||
registerScope("jakarta.inject.Singleton", BeanDefinition.SCOPE_SINGLETON);
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,7 +93,7 @@ public class Jsr330ScopeMetadataResolver implements ScopeMetadataResolver {
|
|||
String found = null;
|
||||
for (String annType : annTypes) {
|
||||
Set<String> metaAnns = annDef.getMetadata().getMetaAnnotationTypes(annType);
|
||||
if (metaAnns.contains("javax.inject.Scope")) {
|
||||
if (metaAnns.contains("jakarta.inject.Scope")) {
|
||||
if (found != null) {
|
||||
throw new IllegalStateException("Found ambiguous scope annotations on bean class [" +
|
||||
definition.getBeanClassName() + "]: " + found + ", " + annType);
|
||||
|
|
|
@ -44,9 +44,9 @@ import java.lang.annotation.Target;
|
|||
*
|
||||
* <p>In addition to its role for component initialization, this annotation may also be placed
|
||||
* on injection points marked with {@link org.springframework.beans.factory.annotation.Autowired}
|
||||
* or {@link javax.inject.Inject}: In that context, it leads to the creation of a
|
||||
* or {@link jakarta.inject.Inject}: In that context, it leads to the creation of a
|
||||
* lazy-resolution proxy for all affected dependencies, as an alternative to using
|
||||
* {@link org.springframework.beans.factory.ObjectFactory} or {@link javax.inject.Provider}.
|
||||
* {@link org.springframework.beans.factory.ObjectFactory} or {@link jakarta.inject.Provider}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -19,7 +19,6 @@ package org.springframework.context.annotation;
|
|||
import java.util.Map;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
|
@ -28,14 +27,10 @@ import org.springframework.context.EnvironmentAware;
|
|||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.jmx.MBeanServerNotFoundException;
|
||||
import org.springframework.jmx.export.annotation.AnnotationMBeanExporter;
|
||||
import org.springframework.jmx.support.RegistrationPolicy;
|
||||
import org.springframework.jmx.support.WebSphereMBeanServerFactoryBean;
|
||||
import org.springframework.jndi.JndiLocatorDelegate;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -116,15 +111,6 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
|
|||
Assert.state(this.beanFactory != null, "No BeanFactory set");
|
||||
exporter.setServer(this.beanFactory.getBean(server, MBeanServer.class));
|
||||
}
|
||||
else {
|
||||
SpecificPlatform specificPlatform = SpecificPlatform.get();
|
||||
if (specificPlatform != null) {
|
||||
MBeanServer mbeanServer = specificPlatform.getMBeanServer();
|
||||
if (mbeanServer != null) {
|
||||
exporter.setServer(mbeanServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupRegistrationPolicy(AnnotationMBeanExporter exporter, AnnotationAttributes enableMBeanExport) {
|
||||
|
@ -132,58 +118,4 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
|
|||
exporter.setRegistrationPolicy(registrationPolicy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specific platforms that might need custom MBean handling.
|
||||
*/
|
||||
public enum SpecificPlatform {
|
||||
|
||||
/**
|
||||
* Weblogic.
|
||||
*/
|
||||
WEBLOGIC("weblogic.management.Helper") {
|
||||
@Override
|
||||
public MBeanServer getMBeanServer() {
|
||||
try {
|
||||
return new JndiLocatorDelegate().lookup("java:comp/env/jmx/runtime", MBeanServer.class);
|
||||
}
|
||||
catch (NamingException ex) {
|
||||
throw new MBeanServerNotFoundException("Failed to retrieve WebLogic MBeanServer from JNDI", ex);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Websphere.
|
||||
*/
|
||||
WEBSPHERE("com.ibm.websphere.management.AdminServiceFactory") {
|
||||
@Override
|
||||
public MBeanServer getMBeanServer() {
|
||||
WebSphereMBeanServerFactoryBean fb = new WebSphereMBeanServerFactoryBean();
|
||||
fb.afterPropertiesSet();
|
||||
return fb.getObject();
|
||||
}
|
||||
};
|
||||
|
||||
private final String identifyingClass;
|
||||
|
||||
SpecificPlatform(String identifyingClass) {
|
||||
this.identifyingClass = identifyingClass;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract MBeanServer getMBeanServer();
|
||||
|
||||
@Nullable
|
||||
public static SpecificPlatform get() {
|
||||
ClassLoader classLoader = MBeanExportConfiguration.class.getClassLoader();
|
||||
for (SpecificPlatform environment : values()) {
|
||||
if (ClassUtils.isPresent(environment.identifyingClass, classLoader)) {
|
||||
return environment;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -76,12 +76,6 @@ class MBeanExportBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
if (StringUtils.hasText(serverBeanName)) {
|
||||
builder.addPropertyReference("server", serverBeanName);
|
||||
}
|
||||
else {
|
||||
AbstractBeanDefinition specialServer = MBeanServerBeanDefinitionParser.findServerForSpecialEnvironment();
|
||||
if (specialServer != null) {
|
||||
builder.addPropertyValue("server", specialServer);
|
||||
}
|
||||
}
|
||||
|
||||
String registration = element.getAttribute(REGISTRATION_ATTRIBUTE);
|
||||
RegistrationPolicy registrationPolicy = RegistrationPolicy.FAIL_ON_EXISTING;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,10 +24,6 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
|||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.jmx.support.MBeanServerFactoryBean;
|
||||
import org.springframework.jmx.support.WebSphereMBeanServerFactoryBean;
|
||||
import org.springframework.jndi.JndiObjectFactoryBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -49,17 +45,6 @@ class MBeanServerBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
private static final String AGENT_ID_ATTRIBUTE = "agent-id";
|
||||
|
||||
|
||||
private static final boolean weblogicPresent;
|
||||
|
||||
private static final boolean webspherePresent;
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = MBeanServerBeanDefinitionParser.class.getClassLoader();
|
||||
weblogicPresent = ClassUtils.isPresent("weblogic.management.Helper", classLoader);
|
||||
webspherePresent = ClassUtils.isPresent("com.ibm.websphere.management.AdminServiceFactory", classLoader);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
|
||||
String id = element.getAttribute(ID_ATTRIBUTE);
|
||||
|
@ -74,10 +59,7 @@ class MBeanServerBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
bd.getPropertyValues().add("agentId", agentId);
|
||||
return bd;
|
||||
}
|
||||
AbstractBeanDefinition specialServer = findServerForSpecialEnvironment();
|
||||
if (specialServer != null) {
|
||||
return specialServer;
|
||||
}
|
||||
|
||||
RootBeanDefinition bd = new RootBeanDefinition(MBeanServerFactoryBean.class);
|
||||
bd.getPropertyValues().add("locateExistingServerIfPossible", Boolean.TRUE);
|
||||
|
||||
|
@ -87,19 +69,4 @@ class MBeanServerBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
|||
return bd;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static AbstractBeanDefinition findServerForSpecialEnvironment() {
|
||||
if (weblogicPresent) {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(JndiObjectFactoryBean.class);
|
||||
bd.getPropertyValues().add("jndiName", "java:comp/env/jmx/runtime");
|
||||
return bd;
|
||||
}
|
||||
else if (webspherePresent) {
|
||||
return new RootBeanDefinition(WebSphereMBeanServerFactoryBean.class);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -30,8 +30,6 @@ import org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver;
|
|||
import org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.jboss.JBossLoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.websphere.WebSphereLoadTimeWeaver;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
@ -45,10 +43,9 @@ import org.springframework.util.Assert;
|
|||
* on a {@code @Configuration} class.
|
||||
*
|
||||
* <p>This class implements a runtime environment check for obtaining the
|
||||
* appropriate weaver implementation. As of Spring Framework 5.0, it detects
|
||||
* Oracle WebLogic 10+, GlassFish 4+, Tomcat 8+, WildFly 8+, IBM WebSphere 8.5+,
|
||||
* {@link InstrumentationSavingAgent Spring's VM agent}, and any {@link ClassLoader}
|
||||
* supported by Spring's {@link ReflectiveLoadTimeWeaver} (such as Liberty's).
|
||||
* appropriate weaver implementation, including
|
||||
* {@link InstrumentationSavingAgent Spring's VM agent} and any {@link ClassLoader}
|
||||
* supported by Spring's {@link ReflectiveLoadTimeWeaver}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
|
@ -120,12 +117,6 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo
|
|||
else if (name.startsWith("org.jboss.modules")) {
|
||||
return new JBossLoadTimeWeaver(classLoader);
|
||||
}
|
||||
else if (name.startsWith("com.ibm.ws.classloader")) {
|
||||
return new WebSphereLoadTimeWeaver(classLoader);
|
||||
}
|
||||
else if (name.startsWith("weblogic")) {
|
||||
return new WebLogicLoadTimeWeaver(classLoader);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
|
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.ejb.access;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.ejb.EJBHome;
|
||||
import javax.ejb.EJBObject;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.remoting.RemoteConnectFailureException;
|
||||
import org.springframework.remoting.RemoteLookupFailureException;
|
||||
|
||||
/**
|
||||
* Base class for interceptors proxying remote Stateless Session Beans.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>Such an interceptor must be the last interceptor in the advice chain.
|
||||
* In this case, there is no target object.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public abstract class AbstractRemoteSlsbInvokerInterceptor extends AbstractSlsbInvokerInterceptor {
|
||||
|
||||
private boolean refreshHomeOnConnectFailure = false;
|
||||
|
||||
private volatile boolean homeAsComponent;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to refresh the EJB home on connect failure.
|
||||
* Default is "false".
|
||||
* <p>Can be turned on to allow for hot restart of the EJB server.
|
||||
* If a cached EJB home throws an RMI exception that indicates a
|
||||
* remote connect failure, a fresh home will be fetched and the
|
||||
* invocation will be retried.
|
||||
* @see java.rmi.ConnectException
|
||||
* @see java.rmi.ConnectIOException
|
||||
* @see java.rmi.NoSuchObjectException
|
||||
*/
|
||||
public void setRefreshHomeOnConnectFailure(boolean refreshHomeOnConnectFailure) {
|
||||
this.refreshHomeOnConnectFailure = refreshHomeOnConnectFailure;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isHomeRefreshable() {
|
||||
return this.refreshHomeOnConnectFailure;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check for EJB3-style home object that serves as EJB component directly.
|
||||
*/
|
||||
@Override
|
||||
protected Method getCreateMethod(Object home) throws EjbAccessException {
|
||||
if (this.homeAsComponent) {
|
||||
return null;
|
||||
}
|
||||
if (!(home instanceof EJBHome)) {
|
||||
// An EJB3 Session Bean...
|
||||
this.homeAsComponent = true;
|
||||
return null;
|
||||
}
|
||||
return super.getCreateMethod(home);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches an EJB home object and delegates to {@code doInvoke}.
|
||||
* <p>If configured to refresh on connect failure, it will call
|
||||
* {@link #refreshAndRetry} on corresponding RMI exceptions.
|
||||
* @see #getHome
|
||||
* @see #doInvoke
|
||||
* @see #refreshAndRetry
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object invokeInContext(MethodInvocation invocation) throws Throwable {
|
||||
try {
|
||||
return doInvoke(invocation);
|
||||
}
|
||||
catch (RemoteConnectFailureException ex) {
|
||||
return handleRemoteConnectFailure(invocation, ex);
|
||||
}
|
||||
catch (RemoteException ex) {
|
||||
if (isConnectFailure(ex)) {
|
||||
return handleRemoteConnectFailure(invocation, ex);
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given RMI exception indicates a connect failure.
|
||||
* <p>The default implementation delegates to RmiClientInterceptorUtils.
|
||||
* @param ex the RMI exception to check
|
||||
* @return whether the exception should be treated as connect failure
|
||||
* @see org.springframework.remoting.rmi.RmiClientInterceptorUtils#isConnectFailure
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected boolean isConnectFailure(RemoteException ex) {
|
||||
return org.springframework.remoting.rmi.RmiClientInterceptorUtils.isConnectFailure(ex);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable {
|
||||
if (this.refreshHomeOnConnectFailure) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not connect to remote EJB [" + getJndiName() + "] - retrying", ex);
|
||||
}
|
||||
else if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not connect to remote EJB [" + getJndiName() + "] - retrying");
|
||||
}
|
||||
return refreshAndRetry(invocation);
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the EJB home object and retry the given invocation.
|
||||
* Called by invoke on connect failure.
|
||||
* @param invocation the AOP method invocation
|
||||
* @return the invocation result, if any
|
||||
* @throws Throwable in case of invocation failure
|
||||
* @see #invoke
|
||||
*/
|
||||
@Nullable
|
||||
protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable {
|
||||
try {
|
||||
refreshHome();
|
||||
}
|
||||
catch (NamingException ex) {
|
||||
throw new RemoteLookupFailureException("Failed to locate remote EJB [" + getJndiName() + "]", ex);
|
||||
}
|
||||
return doInvoke(invocation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform the given invocation on the current EJB home.
|
||||
* Template method to be implemented by subclasses.
|
||||
* @param invocation the AOP method invocation
|
||||
* @return the invocation result, if any
|
||||
* @throws Throwable in case of invocation failure
|
||||
* @see #getHome
|
||||
* @see #newSessionBeanInstance
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract Object doInvoke(MethodInvocation invocation) throws Throwable;
|
||||
|
||||
|
||||
/**
|
||||
* Return a new instance of the stateless session bean.
|
||||
* To be invoked by concrete remote SLSB invoker subclasses.
|
||||
* <p>Can be overridden to change the algorithm.
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
* @see #create
|
||||
*/
|
||||
protected Object newSessionBeanInstance() throws NamingException, InvocationTargetException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Trying to create reference to remote EJB");
|
||||
}
|
||||
Object ejbInstance = create();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Obtained reference to remote EJB: " + ejbInstance);
|
||||
}
|
||||
return ejbInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given EJB instance.
|
||||
* To be invoked by concrete remote SLSB invoker subclasses.
|
||||
* @param ejb the EJB instance to remove
|
||||
* @see javax.ejb.EJBObject#remove
|
||||
*/
|
||||
protected void removeSessionBeanInstance(@Nullable EJBObject ejb) {
|
||||
if (ejb != null && !this.homeAsComponent) {
|
||||
try {
|
||||
ejb.remove();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.warn("Could not invoke 'remove' on remote EJB proxy", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,238 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.ejb.access;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.jndi.JndiObjectLocator;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Base class for AOP interceptors invoking local or remote Stateless Session Beans.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>Such an interceptor must be the last interceptor in the advice chain.
|
||||
* In this case, there is no direct target object: The call is handled in a
|
||||
* special way, getting executed on an EJB instance retrieved via an EJB home.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public abstract class AbstractSlsbInvokerInterceptor extends JndiObjectLocator
|
||||
implements MethodInterceptor {
|
||||
|
||||
private boolean lookupHomeOnStartup = true;
|
||||
|
||||
private boolean cacheHome = true;
|
||||
|
||||
private boolean exposeAccessContext = false;
|
||||
|
||||
/**
|
||||
* The EJB's home object, potentially cached.
|
||||
* The type must be Object as it could be either EJBHome or EJBLocalHome.
|
||||
*/
|
||||
@Nullable
|
||||
private Object cachedHome;
|
||||
|
||||
/**
|
||||
* The no-arg create() method required on EJB homes, potentially cached.
|
||||
*/
|
||||
@Nullable
|
||||
private Method createMethod;
|
||||
|
||||
private final Object homeMonitor = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to look up the EJB home object on startup.
|
||||
* Default is "true".
|
||||
* <p>Can be turned off to allow for late start of the EJB server.
|
||||
* In this case, the EJB home object will be fetched on first access.
|
||||
* @see #setCacheHome
|
||||
*/
|
||||
public void setLookupHomeOnStartup(boolean lookupHomeOnStartup) {
|
||||
this.lookupHomeOnStartup = lookupHomeOnStartup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to cache the EJB home object once it has been located.
|
||||
* Default is "true".
|
||||
* <p>Can be turned off to allow for hot restart of the EJB server.
|
||||
* In this case, the EJB home object will be fetched for each invocation.
|
||||
* @see #setLookupHomeOnStartup
|
||||
*/
|
||||
public void setCacheHome(boolean cacheHome) {
|
||||
this.cacheHome = cacheHome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to expose the JNDI environment context for all access to the target
|
||||
* EJB, i.e. for all method invocations on the exposed object reference.
|
||||
* <p>Default is "false", i.e. to only expose the JNDI context for object lookup.
|
||||
* Switch this flag to "true" in order to expose the JNDI environment (including
|
||||
* the authorization context) for each EJB invocation, as needed by WebLogic
|
||||
* for EJBs with authorization requirements.
|
||||
*/
|
||||
public void setExposeAccessContext(boolean exposeAccessContext) {
|
||||
this.exposeAccessContext = exposeAccessContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches EJB home on startup, if necessary.
|
||||
* @see #setLookupHomeOnStartup
|
||||
* @see #refreshHome
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws NamingException {
|
||||
super.afterPropertiesSet();
|
||||
if (this.lookupHomeOnStartup) {
|
||||
// look up EJB home and create method
|
||||
refreshHome();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the cached home object, if applicable.
|
||||
* Also caches the create method on the home object.
|
||||
* @throws NamingException if thrown by the JNDI lookup
|
||||
* @see #lookup
|
||||
* @see #getCreateMethod
|
||||
*/
|
||||
protected void refreshHome() throws NamingException {
|
||||
synchronized (this.homeMonitor) {
|
||||
Object home = lookup();
|
||||
if (this.cacheHome) {
|
||||
this.cachedHome = home;
|
||||
this.createMethod = getCreateMethod(home);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the create method of the given EJB home object.
|
||||
* @param home the EJB home object
|
||||
* @return the create method
|
||||
* @throws EjbAccessException if the method couldn't be retrieved
|
||||
*/
|
||||
@Nullable
|
||||
protected Method getCreateMethod(Object home) throws EjbAccessException {
|
||||
try {
|
||||
// Cache the EJB create() method that must be declared on the home interface.
|
||||
return home.getClass().getMethod("create");
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new EjbAccessException("EJB home [" + home + "] has no no-arg create() method");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the EJB home object to use. Called for each invocation.
|
||||
* <p>Default implementation returns the home created on initialization,
|
||||
* if any; else, it invokes lookup to get a new proxy for each invocation.
|
||||
* <p>Can be overridden in subclasses, for example to cache a home object
|
||||
* for a given amount of time before recreating it, or to test the home
|
||||
* object whether it is still alive.
|
||||
* @return the EJB home object to use for an invocation
|
||||
* @throws NamingException if proxy creation failed
|
||||
* @see #lookup
|
||||
* @see #getCreateMethod
|
||||
*/
|
||||
protected Object getHome() throws NamingException {
|
||||
if (!this.cacheHome || (this.lookupHomeOnStartup && !isHomeRefreshable())) {
|
||||
return (this.cachedHome != null ? this.cachedHome : lookup());
|
||||
}
|
||||
else {
|
||||
synchronized (this.homeMonitor) {
|
||||
if (this.cachedHome == null) {
|
||||
this.cachedHome = lookup();
|
||||
this.createMethod = getCreateMethod(this.cachedHome);
|
||||
}
|
||||
return this.cachedHome;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the cached EJB home object is potentially
|
||||
* subject to on-demand refreshing. Default is "false".
|
||||
*/
|
||||
protected boolean isHomeRefreshable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepares the thread context if necessary, and delegates to
|
||||
* {@link #invokeInContext}.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
Context ctx = (this.exposeAccessContext ? getJndiTemplate().getContext() : null);
|
||||
try {
|
||||
return invokeInContext(invocation);
|
||||
}
|
||||
finally {
|
||||
getJndiTemplate().releaseContext(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the given invocation on the current EJB home,
|
||||
* within the thread context being prepared accordingly.
|
||||
* Template method to be implemented by subclasses.
|
||||
* @param invocation the AOP method invocation
|
||||
* @return the invocation result, if any
|
||||
* @throws Throwable in case of invocation failure
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract Object invokeInContext(MethodInvocation invocation) throws Throwable;
|
||||
|
||||
|
||||
/**
|
||||
* Invokes the {@code create()} method on the cached EJB home object.
|
||||
* @return a new EJBObject or EJBLocalObject
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
*/
|
||||
protected Object create() throws NamingException, InvocationTargetException {
|
||||
try {
|
||||
Object home = getHome();
|
||||
Method createMethodToUse = this.createMethod;
|
||||
if (createMethodToUse == null) {
|
||||
createMethodToUse = getCreateMethod(home);
|
||||
}
|
||||
if (createMethodToUse == null) {
|
||||
return home;
|
||||
}
|
||||
// Invoke create() method on EJB home object.
|
||||
return createMethodToUse.invoke(home, (Object[]) null);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new EjbAccessException("Could not access EJB home create() method", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.ejb.access;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Exception that gets thrown when an EJB stub cannot be accessed properly.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class EjbAccessException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* Constructor for EjbAccessException.
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public EjbAccessException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for EjbAccessException.
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause
|
||||
*/
|
||||
public EjbAccessException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.ejb.access;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.ejb.CreateException;
|
||||
import javax.ejb.EJBLocalHome;
|
||||
import javax.ejb.EJBLocalObject;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Invoker for a local Stateless Session Bean.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>Caches the home object, since a local EJB home can never go stale.
|
||||
* See {@link org.springframework.jndi.JndiObjectLocator} for info on
|
||||
* how to specify the JNDI location of the target EJB.
|
||||
*
|
||||
* <p>In a bean container, this class is normally best used as a singleton. However,
|
||||
* if that bean container pre-instantiates singletons (as do the XML ApplicationContext
|
||||
* variants) you may have a problem if the bean container is loaded before the EJB
|
||||
* container loads the target EJB. That is because by default the JNDI lookup will be
|
||||
* performed in the init method of this class and cached, but the EJB will not have been
|
||||
* bound at the target location yet. The best solution is to set the lookupHomeOnStartup
|
||||
* property to false, in which case the home will be fetched on first access to the EJB.
|
||||
* (This flag is only true by default for backwards compatibility reasons).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see AbstractSlsbInvokerInterceptor#setLookupHomeOnStartup
|
||||
* @see AbstractSlsbInvokerInterceptor#setCacheHome
|
||||
*/
|
||||
public class LocalSlsbInvokerInterceptor extends AbstractSlsbInvokerInterceptor {
|
||||
|
||||
private volatile boolean homeAsComponent;
|
||||
|
||||
|
||||
/**
|
||||
* This implementation "creates" a new EJB instance for each invocation.
|
||||
* Can be overridden for custom invocation strategies.
|
||||
* <p>Alternatively, override {@link #getSessionBeanInstance} and
|
||||
* {@link #releaseSessionBeanInstance} to change EJB instance creation,
|
||||
* for example to hold a single shared EJB instance.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object invokeInContext(MethodInvocation invocation) throws Throwable {
|
||||
Object ejb = null;
|
||||
try {
|
||||
ejb = getSessionBeanInstance();
|
||||
Method method = invocation.getMethod();
|
||||
if (method.getDeclaringClass().isInstance(ejb)) {
|
||||
// directly implemented
|
||||
return method.invoke(ejb, invocation.getArguments());
|
||||
}
|
||||
else {
|
||||
// not directly implemented
|
||||
Method ejbMethod = ejb.getClass().getMethod(method.getName(), method.getParameterTypes());
|
||||
return ejbMethod.invoke(ejb, invocation.getArguments());
|
||||
}
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
Throwable targetEx = ex.getTargetException();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method of local EJB [" + getJndiName() + "] threw exception", targetEx);
|
||||
}
|
||||
if (targetEx instanceof CreateException) {
|
||||
throw new EjbAccessException("Could not create local EJB [" + getJndiName() + "]", targetEx);
|
||||
}
|
||||
else {
|
||||
throw targetEx;
|
||||
}
|
||||
}
|
||||
catch (NamingException ex) {
|
||||
throw new EjbAccessException("Failed to locate local EJB [" + getJndiName() + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new EjbAccessException("Could not access method [" + invocation.getMethod().getName() +
|
||||
"] of local EJB [" + getJndiName() + "]", ex);
|
||||
}
|
||||
finally {
|
||||
if (ejb instanceof EJBLocalObject) {
|
||||
releaseSessionBeanInstance((EJBLocalObject) ejb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for EJB3-style home object that serves as EJB component directly.
|
||||
*/
|
||||
@Override
|
||||
protected Method getCreateMethod(Object home) throws EjbAccessException {
|
||||
if (this.homeAsComponent) {
|
||||
return null;
|
||||
}
|
||||
if (!(home instanceof EJBLocalHome)) {
|
||||
// An EJB3 Session Bean...
|
||||
this.homeAsComponent = true;
|
||||
return null;
|
||||
}
|
||||
return super.getCreateMethod(home);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an EJB instance to delegate the call to.
|
||||
* Default implementation delegates to newSessionBeanInstance.
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
* @see #newSessionBeanInstance
|
||||
*/
|
||||
protected Object getSessionBeanInstance() throws NamingException, InvocationTargetException {
|
||||
return newSessionBeanInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the given EJB instance.
|
||||
* Default implementation delegates to removeSessionBeanInstance.
|
||||
* @param ejb the EJB instance to release
|
||||
* @see #removeSessionBeanInstance
|
||||
*/
|
||||
protected void releaseSessionBeanInstance(EJBLocalObject ejb) {
|
||||
removeSessionBeanInstance(ejb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of the stateless session bean.
|
||||
* Can be overridden to change the algorithm.
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
* @see #create
|
||||
*/
|
||||
protected Object newSessionBeanInstance() throws NamingException, InvocationTargetException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Trying to create reference to local EJB");
|
||||
}
|
||||
Object ejbInstance = create();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Obtained reference to local EJB: " + ejbInstance);
|
||||
}
|
||||
return ejbInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given EJB instance.
|
||||
* @param ejb the EJB instance to remove
|
||||
* @see javax.ejb.EJBLocalObject#remove()
|
||||
*/
|
||||
protected void removeSessionBeanInstance(@Nullable EJBLocalObject ejb) {
|
||||
if (ejb != null && !this.homeAsComponent) {
|
||||
try {
|
||||
ejb.remove();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.warn("Could not invoke 'remove' on local EJB proxy", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.ejb.access;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Convenient {@link FactoryBean} for local Stateless Session Bean (SLSB) proxies.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>See {@link org.springframework.jndi.JndiObjectLocator} for info on
|
||||
* how to specify the JNDI location of the target EJB.
|
||||
*
|
||||
* <p>If you want control over interceptor chaining, use an AOP ProxyFactoryBean
|
||||
* with LocalSlsbInvokerInterceptor rather than rely on this class.
|
||||
*
|
||||
* <p>In a bean container, this class is normally best used as a singleton. However,
|
||||
* if that bean container pre-instantiates singletons (as do the XML ApplicationContext
|
||||
* variants) you may have a problem if the bean container is loaded before the EJB
|
||||
* container loads the target EJB. That is because by default the JNDI lookup will be
|
||||
* performed in the init method of this class and cached, but the EJB will not have been
|
||||
* bound at the target location yet. The best solution is to set the "lookupHomeOnStartup"
|
||||
* property to "false", in which case the home will be fetched on first access to the EJB.
|
||||
* (This flag is only true by default for backwards compatibility reasons).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Colin Sampaleanu
|
||||
* @since 09.05.2003
|
||||
* @see AbstractSlsbInvokerInterceptor#setLookupHomeOnStartup
|
||||
* @see AbstractSlsbInvokerInterceptor#setCacheHome
|
||||
*/
|
||||
public class LocalStatelessSessionProxyFactoryBean extends LocalSlsbInvokerInterceptor
|
||||
implements FactoryBean<Object>, BeanClassLoaderAware {
|
||||
|
||||
/** The business interface of the EJB we're proxying. */
|
||||
@Nullable
|
||||
private Class<?> businessInterface;
|
||||
|
||||
@Nullable
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
/** EJBLocalObject. */
|
||||
@Nullable
|
||||
private Object proxy;
|
||||
|
||||
|
||||
/**
|
||||
* Set the business interface of the EJB we're proxying.
|
||||
* This will normally be a super-interface of the EJB local component interface.
|
||||
* Using a business methods interface is a best practice when implementing EJBs.
|
||||
* @param businessInterface set the business interface of the EJB
|
||||
*/
|
||||
public void setBusinessInterface(@Nullable Class<?> businessInterface) {
|
||||
this.businessInterface = businessInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the business interface of the EJB we're proxying.
|
||||
*/
|
||||
@Nullable
|
||||
public Class<?> getBusinessInterface() {
|
||||
return this.businessInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws NamingException {
|
||||
super.afterPropertiesSet();
|
||||
if (this.businessInterface == null) {
|
||||
throw new IllegalArgumentException("businessInterface is required");
|
||||
}
|
||||
this.proxy = new ProxyFactory(this.businessInterface, this).getProxy(this.beanClassLoader);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getObject() {
|
||||
return this.proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return this.businessInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.ejb.access;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.ejb.CreateException;
|
||||
import javax.ejb.EJBObject;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.remoting.RemoteLookupFailureException;
|
||||
|
||||
/**
|
||||
* Basic invoker for a remote Stateless Session Bean.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>"Creates" a new EJB instance for each invocation, or caches the session
|
||||
* bean instance for all invocations (see {@link #setCacheSessionBean}).
|
||||
* See {@link org.springframework.jndi.JndiObjectLocator} for info on
|
||||
* how to specify the JNDI location of the target EJB.
|
||||
*
|
||||
* <p>In a bean container, this class is normally best used as a singleton. However,
|
||||
* if that bean container pre-instantiates singletons (as do the XML ApplicationContext
|
||||
* variants) you may have a problem if the bean container is loaded before the EJB
|
||||
* container loads the target EJB. That is because by default the JNDI lookup will be
|
||||
* performed in the init method of this class and cached, but the EJB will not have been
|
||||
* bound at the target location yet. The best solution is to set the "lookupHomeOnStartup"
|
||||
* property to "false", in which case the home will be fetched on first access to the EJB.
|
||||
* (This flag is only true by default for backwards compatibility reasons).
|
||||
*
|
||||
* <p>This invoker is typically used with an RMI business interface, which serves
|
||||
* as super-interface of the EJB component interface. Alternatively, this invoker
|
||||
* can also proxy a remote SLSB with a matching non-RMI business interface, i.e. an
|
||||
* interface that mirrors the EJB business methods but does not declare RemoteExceptions.
|
||||
* In the latter case, RemoteExceptions thrown by the EJB stub will automatically get
|
||||
* converted to Spring's unchecked RemoteAccessException.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 09.05.2003
|
||||
* @see org.springframework.remoting.RemoteAccessException
|
||||
* @see AbstractSlsbInvokerInterceptor#setLookupHomeOnStartup
|
||||
* @see AbstractSlsbInvokerInterceptor#setCacheHome
|
||||
* @see AbstractRemoteSlsbInvokerInterceptor#setRefreshHomeOnConnectFailure
|
||||
*/
|
||||
public class SimpleRemoteSlsbInvokerInterceptor extends AbstractRemoteSlsbInvokerInterceptor
|
||||
implements DisposableBean {
|
||||
|
||||
private boolean cacheSessionBean = false;
|
||||
|
||||
@Nullable
|
||||
private Object beanInstance;
|
||||
|
||||
private final Object beanInstanceMonitor = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to cache the actual session bean object.
|
||||
* <p>Off by default for standard EJB compliance. Turn this flag
|
||||
* on to optimize session bean access for servers that are
|
||||
* known to allow for caching the actual session bean object.
|
||||
* @see #setCacheHome
|
||||
*/
|
||||
public void setCacheSessionBean(boolean cacheSessionBean) {
|
||||
this.cacheSessionBean = cacheSessionBean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation "creates" a new EJB instance for each invocation.
|
||||
* Can be overridden for custom invocation strategies.
|
||||
* <p>Alternatively, override {@link #getSessionBeanInstance} and
|
||||
* {@link #releaseSessionBeanInstance} to change EJB instance creation,
|
||||
* for example to hold a single shared EJB component instance.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Object doInvoke(MethodInvocation invocation) throws Throwable {
|
||||
Object ejb = null;
|
||||
try {
|
||||
ejb = getSessionBeanInstance();
|
||||
return org.springframework.remoting.rmi.RmiClientInterceptorUtils.invokeRemoteMethod(invocation, ejb);
|
||||
}
|
||||
catch (NamingException ex) {
|
||||
throw new RemoteLookupFailureException("Failed to locate remote EJB [" + getJndiName() + "]", ex);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
Throwable targetEx = ex.getTargetException();
|
||||
if (targetEx instanceof RemoteException) {
|
||||
RemoteException rex = (RemoteException) targetEx;
|
||||
throw org.springframework.remoting.rmi.RmiClientInterceptorUtils.convertRmiAccessException(
|
||||
invocation.getMethod(), rex, isConnectFailure(rex), getJndiName());
|
||||
}
|
||||
else if (targetEx instanceof CreateException) {
|
||||
throw org.springframework.remoting.rmi.RmiClientInterceptorUtils.convertRmiAccessException(
|
||||
invocation.getMethod(), targetEx, "Could not create remote EJB [" + getJndiName() + "]");
|
||||
}
|
||||
throw targetEx;
|
||||
}
|
||||
finally {
|
||||
if (ejb instanceof EJBObject) {
|
||||
releaseSessionBeanInstance((EJBObject) ejb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an EJB component instance to delegate the call to.
|
||||
* <p>The default implementation delegates to {@link #newSessionBeanInstance}.
|
||||
* @return the EJB component instance
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
* @see #newSessionBeanInstance
|
||||
*/
|
||||
protected Object getSessionBeanInstance() throws NamingException, InvocationTargetException {
|
||||
if (this.cacheSessionBean) {
|
||||
synchronized (this.beanInstanceMonitor) {
|
||||
if (this.beanInstance == null) {
|
||||
this.beanInstance = newSessionBeanInstance();
|
||||
}
|
||||
return this.beanInstance;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return newSessionBeanInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the given EJB instance.
|
||||
* <p>The default implementation delegates to {@link #removeSessionBeanInstance}.
|
||||
* @param ejb the EJB component instance to release
|
||||
* @see #removeSessionBeanInstance
|
||||
*/
|
||||
protected void releaseSessionBeanInstance(EJBObject ejb) {
|
||||
if (!this.cacheSessionBean) {
|
||||
removeSessionBeanInstance(ejb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the cached session bean instance, if necessary.
|
||||
*/
|
||||
@Override
|
||||
protected void refreshHome() throws NamingException {
|
||||
super.refreshHome();
|
||||
if (this.cacheSessionBean) {
|
||||
synchronized (this.beanInstanceMonitor) {
|
||||
this.beanInstance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the cached session bean instance, if necessary.
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (this.cacheSessionBean) {
|
||||
synchronized (this.beanInstanceMonitor) {
|
||||
if (this.beanInstance instanceof EJBObject) {
|
||||
removeSessionBeanInstance((EJBObject) this.beanInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.ejb.access;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Convenient {@link FactoryBean} for remote SLSB proxies.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>See {@link org.springframework.jndi.JndiObjectLocator} for info on
|
||||
* how to specify the JNDI location of the target EJB.
|
||||
*
|
||||
* <p>If you want control over interceptor chaining, use an AOP ProxyFactoryBean
|
||||
* with SimpleRemoteSlsbInvokerInterceptor rather than rely on this class.
|
||||
*
|
||||
* <p>In a bean container, this class is normally best used as a singleton. However,
|
||||
* if that bean container pre-instantiates singletons (as do the XML ApplicationContext
|
||||
* variants) you may have a problem if the bean container is loaded before the EJB
|
||||
* container loads the target EJB. That is because by default the JNDI lookup will be
|
||||
* performed in the init method of this class and cached, but the EJB will not have been
|
||||
* bound at the target location yet. The best solution is to set the lookupHomeOnStartup
|
||||
* property to false, in which case the home will be fetched on first access to the EJB.
|
||||
* (This flag is only true by default for backwards compatibility reasons).
|
||||
*
|
||||
* <p>This proxy factory is typically used with an RMI business interface, which serves
|
||||
* as super-interface of the EJB component interface. Alternatively, this factory
|
||||
* can also proxy a remote SLSB with a matching non-RMI business interface, i.e. an
|
||||
* interface that mirrors the EJB business methods but does not declare RemoteExceptions.
|
||||
* In the latter case, RemoteExceptions thrown by the EJB stub will automatically get
|
||||
* converted to Spring's unchecked RemoteAccessException.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Colin Sampaleanu
|
||||
* @author Juergen Hoeller
|
||||
* @since 09.05.2003
|
||||
* @see org.springframework.remoting.RemoteAccessException
|
||||
* @see AbstractSlsbInvokerInterceptor#setLookupHomeOnStartup
|
||||
* @see AbstractSlsbInvokerInterceptor#setCacheHome
|
||||
* @see AbstractRemoteSlsbInvokerInterceptor#setRefreshHomeOnConnectFailure
|
||||
*/
|
||||
public class SimpleRemoteStatelessSessionProxyFactoryBean extends SimpleRemoteSlsbInvokerInterceptor
|
||||
implements FactoryBean<Object>, BeanClassLoaderAware {
|
||||
|
||||
/** The business interface of the EJB we're proxying. */
|
||||
@Nullable
|
||||
private Class<?> businessInterface;
|
||||
|
||||
@Nullable
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
/** EJBObject. */
|
||||
@Nullable
|
||||
private Object proxy;
|
||||
|
||||
|
||||
/**
|
||||
* Set the business interface of the EJB we're proxying.
|
||||
* This will normally be a super-interface of the EJB remote component interface.
|
||||
* Using a business methods interface is a best practice when implementing EJBs.
|
||||
* <p>You can also specify a matching non-RMI business interface, i.e. an interface
|
||||
* that mirrors the EJB business methods but does not declare RemoteExceptions.
|
||||
* In this case, RemoteExceptions thrown by the EJB stub will automatically get
|
||||
* converted to Spring's generic RemoteAccessException.
|
||||
* @param businessInterface the business interface of the EJB
|
||||
*/
|
||||
public void setBusinessInterface(@Nullable Class<?> businessInterface) {
|
||||
this.businessInterface = businessInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the business interface of the EJB we're proxying.
|
||||
*/
|
||||
@Nullable
|
||||
public Class<?> getBusinessInterface() {
|
||||
return this.businessInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws NamingException {
|
||||
super.afterPropertiesSet();
|
||||
if (this.businessInterface == null) {
|
||||
throw new IllegalArgumentException("businessInterface is required");
|
||||
}
|
||||
this.proxy = new ProxyFactory(this.businessInterface, this).getProxy(this.beanClassLoader);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getObject() {
|
||||
return this.proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return this.businessInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/**
|
||||
* This package contains classes that allow easy access to EJBs.
|
||||
* The basis are AOP interceptors run before and after the EJB invocation.
|
||||
* In particular, the classes in this package allow transparent access
|
||||
* to stateless session beans (SLSBs) with local interfaces, avoiding
|
||||
* the need for application code using them to use EJB-specific APIs
|
||||
* and JNDI lookups, and work with business interfaces that could be
|
||||
* implemented without using EJB. This provides a valuable decoupling
|
||||
* of client (such as web components) and business objects (which may
|
||||
* or may not be EJBs). This gives us the choice of introducing EJB
|
||||
* into an application (or removing EJB from an application) without
|
||||
* affecting code using business objects.
|
||||
*
|
||||
* <p>The motivation for the classes in this package is discussed in Chapter 11 of
|
||||
* <a href="https://www.amazon.com/exec/obidos/tg/detail/-/0764543857/">Expert One-On-One J2EE Design and Development</a>
|
||||
* by Rod Johnson (Wrox, 2002).
|
||||
*
|
||||
* <p>However, the implementation and naming of classes in this package has changed.
|
||||
* It now uses FactoryBeans and AOP, rather than the custom bean definitions described in
|
||||
* <i>Expert One-on-One J2EE</i>.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.ejb.access;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,12 +18,12 @@ package org.springframework.ejb.config;
|
|||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean;
|
||||
import org.springframework.jndi.JndiObjectFactoryBean;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser}
|
||||
* implementation for parsing '{@code local-slsb}' tags and
|
||||
* creating {@link LocalStatelessSessionProxyFactoryBean} definitions.
|
||||
* creating plain {@link JndiObjectFactoryBean} definitions.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
|
@ -32,8 +32,8 @@ import org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean;
|
|||
class LocalStatelessSessionBeanDefinitionParser extends AbstractJndiLocatingBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean";
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return JndiObjectFactoryBean.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,12 +18,12 @@ package org.springframework.ejb.config;
|
|||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean;
|
||||
import org.springframework.jndi.JndiObjectFactoryBean;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser}
|
||||
* implementation for parsing '{@code remote-slsb}' tags and
|
||||
* creating {@link SimpleRemoteStatelessSessionProxyFactoryBean} definitions.
|
||||
* creating plain {@link JndiObjectFactoryBean} definitions.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
|
@ -32,8 +32,8 @@ import org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBe
|
|||
class RemoteStatelessSessionBeanDefinitionParser extends AbstractJndiLocatingBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean";
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return JndiObjectFactoryBean.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Support package for EJB/Java EE-related configuration,
|
||||
* Support package for EJB/Jakarta EE-related configuration,
|
||||
* with XML schema being the primary configuration format.
|
||||
*/
|
||||
@NonNullApi
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.instrument.classloading.weblogic;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Reflective wrapper around a WebLogic 10 class loader. Used to
|
||||
* encapsulate the classloader-specific methods (discovered and
|
||||
* called through reflection) from the load-time weaver.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
class WebLogicClassLoaderAdapter {
|
||||
|
||||
private static final String GENERIC_CLASS_LOADER_NAME = "weblogic.utils.classloaders.GenericClassLoader";
|
||||
|
||||
private static final String CLASS_PRE_PROCESSOR_NAME = "weblogic.utils.classloaders.ClassPreProcessor";
|
||||
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
private final Class<?> wlPreProcessorClass;
|
||||
|
||||
private final Method addPreProcessorMethod;
|
||||
|
||||
private final Method getClassFinderMethod;
|
||||
|
||||
private final Method getParentMethod;
|
||||
|
||||
private final Constructor<?> wlGenericClassLoaderConstructor;
|
||||
|
||||
|
||||
public WebLogicClassLoaderAdapter(ClassLoader classLoader) {
|
||||
Class<?> wlGenericClassLoaderClass;
|
||||
try {
|
||||
wlGenericClassLoaderClass = classLoader.loadClass(GENERIC_CLASS_LOADER_NAME);
|
||||
this.wlPreProcessorClass = classLoader.loadClass(CLASS_PRE_PROCESSOR_NAME);
|
||||
this.addPreProcessorMethod = classLoader.getClass().getMethod(
|
||||
"addInstanceClassPreProcessor", this.wlPreProcessorClass);
|
||||
this.getClassFinderMethod = classLoader.getClass().getMethod("getClassFinder");
|
||||
this.getParentMethod = classLoader.getClass().getMethod("getParent");
|
||||
this.wlGenericClassLoaderConstructor = wlGenericClassLoaderClass.getConstructor(
|
||||
this.getClassFinderMethod.getReturnType(), ClassLoader.class);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException(
|
||||
"Could not initialize WebLogic LoadTimeWeaver because WebLogic 10 API classes are not available", ex);
|
||||
}
|
||||
|
||||
if (!wlGenericClassLoaderClass.isInstance(classLoader)) {
|
||||
throw new IllegalArgumentException(
|
||||
"ClassLoader must be an instance of [" + wlGenericClassLoaderClass.getName() + "]: " + classLoader);
|
||||
}
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) {
|
||||
Assert.notNull(transformer, "ClassFileTransformer must not be null");
|
||||
try {
|
||||
InvocationHandler adapter = new WebLogicClassPreProcessorAdapter(transformer, this.classLoader);
|
||||
Object adapterInstance = Proxy.newProxyInstance(this.wlPreProcessorClass.getClassLoader(),
|
||||
new Class<?>[] {this.wlPreProcessorClass}, adapter);
|
||||
this.addPreProcessorMethod.invoke(this.classLoader, adapterInstance);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw new IllegalStateException("WebLogic addInstanceClassPreProcessor method threw exception", ex.getCause());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Could not invoke WebLogic addInstanceClassPreProcessor method", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return this.classLoader;
|
||||
}
|
||||
|
||||
public ClassLoader getThrowawayClassLoader() {
|
||||
try {
|
||||
Object classFinder = this.getClassFinderMethod.invoke(this.classLoader);
|
||||
Object parent = this.getParentMethod.invoke(this.classLoader);
|
||||
// arguments for 'clone'-like method
|
||||
return (ClassLoader) this.wlGenericClassLoaderConstructor.newInstance(classFinder, parent);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw new IllegalStateException("WebLogic GenericClassLoader constructor failed", ex.getCause());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Could not construct WebLogic GenericClassLoader", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.instrument.classloading.weblogic;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Adapter that implements WebLogic ClassPreProcessor interface, delegating to a
|
||||
* standard JDK {@link ClassFileTransformer} underneath.
|
||||
*
|
||||
* <p>To avoid compile time checks again the vendor API, a dynamic proxy is
|
||||
* being used.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
class WebLogicClassPreProcessorAdapter implements InvocationHandler {
|
||||
|
||||
private final ClassFileTransformer transformer;
|
||||
|
||||
private final ClassLoader loader;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new {@link WebLogicClassPreProcessorAdapter}.
|
||||
*/
|
||||
public WebLogicClassPreProcessorAdapter(ClassFileTransformer transformer, ClassLoader loader) {
|
||||
this.transformer = transformer;
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String name = method.getName();
|
||||
if ("equals".equals(name)) {
|
||||
return (proxy == args[0]);
|
||||
}
|
||||
else if ("hashCode".equals(name)) {
|
||||
return hashCode();
|
||||
}
|
||||
else if ("toString".equals(name)) {
|
||||
return toString();
|
||||
}
|
||||
else if ("initialize".equals(name)) {
|
||||
initialize((Hashtable<?, ?>) args[0]);
|
||||
return null;
|
||||
}
|
||||
else if ("preProcess".equals(name)) {
|
||||
return preProcess((String) args[0], (byte[]) args[1]);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown method: " + method);
|
||||
}
|
||||
}
|
||||
|
||||
public void initialize(Hashtable<?, ?> params) {
|
||||
}
|
||||
|
||||
public byte[] preProcess(String className, byte[] classBytes) {
|
||||
try {
|
||||
byte[] result = this.transformer.transform(this.loader, className, null, null, classBytes);
|
||||
return (result != null ? result : classBytes);
|
||||
}
|
||||
catch (IllegalClassFormatException ex) {
|
||||
throw new IllegalStateException("Cannot transform due to illegal class format", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + " for transformer: " + this.transformer;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,78 +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.instrument.classloading.weblogic;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
|
||||
import org.springframework.core.OverridingClassLoader;
|
||||
import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link LoadTimeWeaver} implementation for WebLogic's instrumentable
|
||||
* ClassLoader.
|
||||
*
|
||||
* <p><b>NOTE:</b> Requires BEA WebLogic version 10 or higher.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public class WebLogicLoadTimeWeaver implements LoadTimeWeaver {
|
||||
|
||||
private final WebLogicClassLoaderAdapter classLoader;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link WebLogicLoadTimeWeaver} class using
|
||||
* the default {@link ClassLoader class loader}.
|
||||
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
|
||||
*/
|
||||
public WebLogicLoadTimeWeaver() {
|
||||
this(ClassUtils.getDefaultClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link WebLogicLoadTimeWeaver} class using
|
||||
* the supplied {@link ClassLoader}.
|
||||
* @param classLoader the {@code ClassLoader} to delegate to for weaving
|
||||
*/
|
||||
public WebLogicLoadTimeWeaver(@Nullable ClassLoader classLoader) {
|
||||
Assert.notNull(classLoader, "ClassLoader must not be null");
|
||||
this.classLoader = new WebLogicClassLoaderAdapter(classLoader);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addTransformer(ClassFileTransformer transformer) {
|
||||
this.classLoader.addTransformer(transformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getInstrumentableClassLoader() {
|
||||
return this.classLoader.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getThrowawayClassLoader() {
|
||||
return new OverridingClassLoader(this.classLoader.getClassLoader(),
|
||||
this.classLoader.getThrowawayClassLoader());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
/**
|
||||
* Support for class instrumentation on BEA WebLogic 10+.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.instrument.classloading.weblogic;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue