diff --git a/build.gradle b/build.gradle
index b6e1b8a03fcd..bf5df93e859c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ buildscript {
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.3")
- classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.4")
+ classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.6")
}
}
@@ -12,7 +12,7 @@ configure(allprojects) { project ->
group = "org.springframework"
version = qualifyVersionIfNecessary(version)
- ext.aspectjVersion = "1.7.1"
+ ext.aspectjVersion = "1.7.2"
ext.easymockVersion = "2.5.2"
ext.hsqldbVersion = "1.8.0.10"
ext.junitVersion = "4.11"
diff --git a/buildSrc/src/main/groovy/org/springframework/build/gradle/MergePlugin.groovy b/buildSrc/src/main/groovy/org/springframework/build/gradle/MergePlugin.groovy
index 510a2698c6ae..4143780702b6 100644
--- a/buildSrc/src/main/groovy/org/springframework/build/gradle/MergePlugin.groovy
+++ b/buildSrc/src/main/groovy/org/springframework/build/gradle/MergePlugin.groovy
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -110,7 +110,7 @@ class MergePlugin implements Plugin {
// update 'into' project artifacts to contain the source artifact contents
project.merge.into.sourcesJar.from(project.sourcesJar.source)
- project.merge.into.jar.from(project.jar.source)
+ project.merge.into.jar.from(project.sourceSets.main.output)
project.merge.into.javadoc {
source += project.javadoc.source
classpath += project.javadoc.classpath
diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java
index 96237b86d173..7fbfbf560445 100644
--- a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java
+++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -17,8 +17,8 @@
package org.springframework.aop.interceptor;
import java.lang.reflect.Method;
-import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import org.springframework.beans.BeansException;
@@ -45,7 +45,7 @@
*/
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
- private final Map executors = new HashMap();
+ private final Map executors = new ConcurrentHashMap(16);
private Executor defaultExecutor;
@@ -59,7 +59,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* @param defaultExecutor the executor to use when executing asynchronous methods
*/
public AsyncExecutionAspectSupport(Executor defaultExecutor) {
- this.setExecutor(defaultExecutor);
+ this.defaultExecutor = defaultExecutor;
}
@@ -90,24 +90,25 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
* @return the executor to use (never {@code null})
*/
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
- if (!this.executors.containsKey(method)) {
- Executor executor = this.defaultExecutor;
+ AsyncTaskExecutor executor = this.executors.get(method);
+ if (executor == null) {
+ Executor executorToUse = this.defaultExecutor;
String qualifier = getExecutorQualifier(method);
if (StringUtils.hasLength(qualifier)) {
- Assert.notNull(this.beanFactory,
- "BeanFactory must be set on " + this.getClass().getSimpleName() +
- " to access qualified executor [" + qualifier + "]");
- executor = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
+ Assert.notNull(this.beanFactory, "BeanFactory must be set on " + getClass().getSimpleName() +
+ " to access qualified executor '" + qualifier + "'");
+ executorToUse = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
this.beanFactory, Executor.class, qualifier);
}
- if (executor instanceof AsyncTaskExecutor) {
- this.executors.put(method, (AsyncTaskExecutor) executor);
- }
- else if (executor != null) {
- this.executors.put(method, new TaskExecutorAdapter(executor));
+ else if (executorToUse == null) {
+ throw new IllegalStateException("No executor qualifier specified and no default executor set on " +
+ getClass().getSimpleName() + " either");
}
+ executor = (executorToUse instanceof AsyncTaskExecutor ?
+ (AsyncTaskExecutor) executorToUse : new TaskExecutorAdapter(executorToUse));
+ this.executors.put(method, executor);
}
- return this.executors.get(method);
+ return executor;
}
/**
diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java
index 792639b1c6f0..daa23a329364 100644
--- a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java
+++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -17,7 +17,6 @@
package org.springframework.aop.interceptor;
import java.lang.reflect.Method;
-
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
@@ -25,8 +24,11 @@
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.Ordered;
import org.springframework.core.task.AsyncTaskExecutor;
+import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -76,7 +78,11 @@ public AsyncExecutionInterceptor(Executor executor) {
* otherwise.
*/
public Object invoke(final MethodInvocation invocation) throws Throwable {
- Future> result = this.determineAsyncExecutor(invocation.getMethod()).submit(
+ Class> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
+ Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
+ specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
+
+ Future> result = determineAsyncExecutor(specificMethod).submit(
new Callable
. Since aspects cannot introduce a private member,
+ * {@code private}. Since aspects cannot introduce a private member,
* while preserving its name, this option is ruled out.
- *
readResolve(): Java doesn't pose any restriction on an access specifier.
- * Problem solved! There is one (minor) limitation of this approach in
- * that if a user class already has this method, that method must be
- * public. However, this shouldn't be a big burden, since
- * use cases that need classes to implement readResolve() (custom enums,
+ *
readResolve(): Java doesn't pose any restriction on an access specifier.
+ * Problem solved! There is one (minor) limitation of this approach in
+ * that if a user class already has this method, that method must be
+ * {@code public}. However, this shouldn't be a big burden, since
+ * use cases that need classes to implement readResolve() (custom enums,
* for example) are unlikely to be marked as @Configurable, and
- * in any case asking to make that method public should not
+ * in any case asking to make that method {@code public} should not
* pose any undue burden.
*
- * The minor collaboration needed by user classes (i.e., that the
- * implementation of readResolve(), if any, must be
- * public) can be lifted as well if we were to use an
- * experimental feature in AspectJ - the hasmethod() PCD.
+ * The minor collaboration needed by user classes (i.e., that the
+ * implementation of {@code readResolve()}, if any, must be
+ * {@code public}) can be lifted as well if we were to use an
+ * experimental feature in AspectJ - the {@code hasmethod()} PCD.
*
*
@@ -63,7 +63,7 @@ import java.io.Serializable;
* is to use a 'declare parents' statement another aspect (a subaspect of this aspect would be a logical choice)
* that declares the classes that need to be configured by supplying the {@link ConfigurableObject} interface.
*
- *
+ *
* @author Ramnivas Laddad
* @since 2.5.2
*/
@@ -71,8 +71,8 @@ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends
/**
* Select initialization join point as object construction
*/
- public pointcut beanConstruction(Object bean) :
- initialization(ConfigurableObject+.new(..)) && this(bean);
+ public pointcut beanConstruction(Object bean) :
+ initialization(ConfigurableObject+.new(..)) && this(bean);
/**
* Select deserialization join point made available through ITDs for ConfigurableDeserializationSupport
@@ -80,40 +80,40 @@ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends
public pointcut beanDeserialization(Object bean) :
execution(Object ConfigurableDeserializationSupport+.readResolve()) &&
this(bean);
-
+
public pointcut leastSpecificSuperTypeConstruction() : initialization(ConfigurableObject.new(..));
-
-
-
+
+
+
// Implementation to support re-injecting dependencies once an object is deserialized
/**
- * Declare any class implementing Serializable and ConfigurableObject as also implementing
- * ConfigurableDeserializationSupport. This allows us to introduce the readResolve()
+ * Declare any class implementing Serializable and ConfigurableObject as also implementing
+ * ConfigurableDeserializationSupport. This allows us to introduce the readResolve()
* method and select it with the beanDeserialization() pointcut.
- *
+ *
*
Here is an improved version that uses the hasmethod() pointcut and lifts
* even the minor requirement on user classes:
*
*
*/
- declare parents:
+ declare parents:
ConfigurableObject+ && Serializable+ implements ConfigurableDeserializationSupport;
-
+
/**
- * A marker interface to which the readResolve() is introduced.
+ * A marker interface to which the {@code readResolve()} is introduced.
*/
static interface ConfigurableDeserializationSupport extends Serializable {
}
-
+
/**
- * Introduce the readResolve() method so that we can advise its
+ * Introduce the {@code readResolve()} method so that we can advise its
* execution to configure the object.
- *
+ *
*
Note if a method with the same signature already exists in a
- * Serializable class of ConfigurableObject type,
+ * {@code Serializable} class of ConfigurableObject type,
* that implementation will take precedence (a good thing, since we are
* merely interested in an opportunity to detect deserialization.)
*/
diff --git a/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AnnotationBeanConfigurerAspect.aj b/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AnnotationBeanConfigurerAspect.aj
index 4cdc292dbbcc..2f1e91ccd23e 100644
--- a/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AnnotationBeanConfigurerAspect.aj
+++ b/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/AnnotationBeanConfigurerAspect.aj
@@ -18,6 +18,7 @@ package org.springframework.beans.factory.aspectj;
import java.io.Serializable;
+import org.aspectj.lang.annotation.control.CodeGenerationHint;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
@@ -32,7 +33,7 @@ import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
* annotation to identify which classes need autowiring.
*
*
The bean name to look up will be taken from the
- * @Configurable annotation if specified, otherwise the
+ * {@code @Configurable} annotation if specified, otherwise the
* default bean name to look up will be the FQN of the class being configured.
*
* @author Rod Johnson
@@ -43,7 +44,7 @@ import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
* @see org.springframework.beans.factory.annotation.Configurable
* @see org.springframework.beans.factory.annotation.AnnotationBeanWiringInfoResolver
*/
-public aspect AnnotationBeanConfigurerAspect
+public aspect AnnotationBeanConfigurerAspect
extends AbstractInterfaceDrivenDependencyInjectionAspect
implements BeanFactoryAware, InitializingBean, DisposableBean {
@@ -51,7 +52,7 @@ public aspect AnnotationBeanConfigurerAspect
public pointcut inConfigurableBean() : @this(Configurable);
- public pointcut preConstructionConfiguration() : preConstructionConfigurationSupport(*);
+ public pointcut preConstructionConfiguration() : preConstructionConfigurationSupport(*);
declare parents: @Configurable * implements ConfigurableObject;
@@ -77,13 +78,14 @@ public aspect AnnotationBeanConfigurerAspect
/*
* An intermediary to match preConstructionConfiguration signature (that doesn't expose the annotation object)
*/
+ @CodeGenerationHint(ifNameSuffix="bb0")
private pointcut preConstructionConfigurationSupport(Configurable c) : @this(c) && if(c.preConstruction());
/*
- * This declaration shouldn't be needed,
+ * This declaration shouldn't be needed,
* except for an AspectJ bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=214559)
*/
- declare parents: @Configurable Serializable+
+ declare parents: @Configurable Serializable+
implements ConfigurableDeserializationSupport;
}
diff --git a/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/GenericInterfaceDrivenDependencyInjectionAspect.aj b/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/GenericInterfaceDrivenDependencyInjectionAspect.aj
index 03f446ca7893..b4a3d93d1d3a 100644
--- a/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/GenericInterfaceDrivenDependencyInjectionAspect.aj
+++ b/spring-aspects/src/main/java/org/springframework/beans/factory/aspectj/GenericInterfaceDrivenDependencyInjectionAspect.aj
@@ -17,24 +17,24 @@ package org.springframework.beans.factory.aspectj;
/**
* Generic-based dependency injection aspect.
- *
- * This aspect allows users to implement efficient, type-safe dependency injection without
+ *
+ * This aspect allows users to implement efficient, type-safe dependency injection without
* the use of the @Configurable annotation.
- *
- * The subaspect of this aspect doesn't need to include any AOP constructs.
- * For example, here is a subaspect that configures the PricingStrategyClient objects.
+ *
+ * The subaspect of this aspect doesn't need to include any AOP constructs.
+ * For example, here is a subaspect that configures the {@code PricingStrategyClient} objects.
*
* @author Ramnivas Laddad
@@ -42,13 +42,13 @@ package org.springframework.beans.factory.aspectj;
*/
public abstract aspect GenericInterfaceDrivenDependencyInjectionAspect extends AbstractInterfaceDrivenDependencyInjectionAspect {
declare parents: I implements ConfigurableObject;
-
+
public pointcut inConfigurableBean() : within(I+);
-
+
public final void configureBean(Object bean) {
configure((I)bean);
}
-
- // Unfortunately, erasure used with generics won't allow to use the same named method
+
+ // Unfortunately, erasure used with generics won't allow to use the same named method
protected abstract void configure(I bean);
}
diff --git a/spring-aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj b/spring-aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj
index dbe15b8fb3a2..ce68942d4058 100644
--- a/spring-aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj
+++ b/spring-aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj
@@ -62,7 +62,7 @@ public abstract aspect AbstractCacheAspect extends CacheAspectSupport {
}
};
- return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs());
+ return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs());
}
/**
diff --git a/spring-aspects/src/main/java/org/springframework/mock/staticmock/AbstractMethodMockingControl.aj b/spring-aspects/src/main/java/org/springframework/mock/staticmock/AbstractMethodMockingControl.aj
index 7ab3fcd0c34a..972a32485939 100644
--- a/spring-aspects/src/main/java/org/springframework/mock/staticmock/AbstractMethodMockingControl.aj
+++ b/spring-aspects/src/main/java/org/springframework/mock/staticmock/AbstractMethodMockingControl.aj
@@ -23,9 +23,9 @@ import java.util.List;
/**
* Abstract aspect to enable mocking of methods picked out by a pointcut.
* Sub-aspects must define the mockStaticsTestMethod() pointcut to
- * indicate call stacks when mocking should be triggered, and the
+ * indicate call stacks when mocking should be triggered, and the
* methodToMock() pointcut to pick out a method invocations to mock.
- *
+ *
* @author Rod Johnson
* @author Ramnivas Laddad
*/
@@ -42,7 +42,7 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
// Represents a list of expected calls to static entity methods
// Public to allow inserted code to access: is this normal??
public class Expectations {
-
+
// Represents an expected call to a static entity method
private class Call {
private final String signature;
@@ -50,21 +50,21 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
private Object responseObject; // return value or throwable
private CallResponse responseType = CallResponse.nothing;
-
+
public Call(String name, Object[] args) {
this.signature = name;
this.args = args;
}
-
+
public boolean hasResponseSpecified() {
return responseType != CallResponse.nothing;
}
-
+
public void setReturnVal(Object retVal) {
this.responseObject = retVal;
responseType = CallResponse.return_;
}
-
+
public void setThrow(Throwable throwable) {
this.responseObject = throwable;
responseType = CallResponse.throw_;
@@ -89,7 +89,7 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
}
}
}
-
+
private List calls = new LinkedList();
// Calls already verified
@@ -101,7 +101,7 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
+ " calls, received " + verified);
}
}
-
+
/**
* Validate the call and provide the expected return value
* @param lastSig
@@ -175,7 +175,7 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
}
}
-
+
public void expectReturnInternal(Object retVal) {
if (!recording) {
throw new IllegalStateException("Not recording: Cannot set return value");
diff --git a/spring-aspects/src/main/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControl.aj b/spring-aspects/src/main/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControl.aj
index 031978ca91f5..816f6a1e424a 100644
--- a/spring-aspects/src/main/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControl.aj
+++ b/spring-aspects/src/main/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControl.aj
@@ -18,16 +18,16 @@ package org.springframework.mock.staticmock;
/**
* Annotation-based aspect to use in test build to enable mocking static methods
- * on JPA-annotated @Entity classes, as used by Roo for finders.
+ * on JPA-annotated {@code @Entity} classes, as used by Roo for finders.
*
- *
Mocking will occur in the call stack of any method in a class (typically a test class)
- * that is annotated with the @MockStaticEntityMethods annotation.
+ *
Mocking will occur in the call stack of any method in a class (typically a test class)
+ * that is annotated with the @MockStaticEntityMethods annotation.
*
*
Also provides static methods to simplify the programming model for
* entering playback mode and setting expected return values.
*
*
Usage:
- *
+ *
*
Annotate a test class with @MockStaticEntityMethods.
*
In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
* Invoke static methods on Entity classes, with each recording-mode invocation
@@ -37,20 +37,20 @@ package org.springframework.mock.staticmock;
*
Call the code you wish to test that uses the static methods. Verification will
* occur automatically.
*
- *
+ *
* @author Rod Johnson
* @author Ramnivas Laddad
* @see MockStaticEntityMethods
*/
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
-
+
/**
* Stop recording mock calls and enter playback state
*/
public static void playback() {
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
}
-
+
public static void expectReturn(Object retVal) {
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
}
diff --git a/spring-aspects/src/main/java/org/springframework/orm/jpa/aspectj/JpaExceptionTranslatorAspect.aj b/spring-aspects/src/main/java/org/springframework/orm/jpa/aspectj/JpaExceptionTranslatorAspect.aj
index 6ff44249d082..131c82beefdc 100644
--- a/spring-aspects/src/main/java/org/springframework/orm/jpa/aspectj/JpaExceptionTranslatorAspect.aj
+++ b/spring-aspects/src/main/java/org/springframework/orm/jpa/aspectj/JpaExceptionTranslatorAspect.aj
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2002-2013 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package org.springframework.orm.jpa.aspectj;
import javax.persistence.EntityManager;
@@ -9,14 +25,17 @@ import org.springframework.dao.DataAccessException;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
public aspect JpaExceptionTranslatorAspect {
- pointcut entityManagerCall(): call(* EntityManager.*(..)) || call(* EntityManagerFactory.*(..)) || call(* EntityTransaction.*(..)) || call(* Query.*(..));
-
- after() throwing(RuntimeException re): entityManagerCall() {
- DataAccessException dex = EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(re);
- if (dex != null) {
- throw dex;
- } else {
- throw re;
- }
- }
+ pointcut entityManagerCall():
+ call(* EntityManager.*(..)) || call(* EntityManagerFactory.*(..)) ||
+ call(* EntityTransaction.*(..)) || call(* Query.*(..));
+
+ after() throwing(RuntimeException re): entityManagerCall() {
+ DataAccessException dex = EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(re);
+ if (dex != null) {
+ throw dex;
+ }
+ else {
+ throw re;
+ }
+ }
}
\ No newline at end of file
diff --git a/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj b/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj
index 6cb3ad60e398..660b35c13614 100644
--- a/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj
+++ b/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj
@@ -28,7 +28,7 @@ import org.springframework.core.task.AsyncTaskExecutor;
/**
* Abstract aspect that routes selected methods asynchronously.
*
- *
This aspect needs to be injected with an implementation of
+ *
This aspect needs to be injected with an implementation of
* {@link Executor} to activate it for a specific thread pool.
* Otherwise it will simply delegate all calls synchronously.
*
diff --git a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj
index 54bd4ef7464f..f9c70661ae1f 100644
--- a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj
+++ b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj
@@ -16,8 +16,6 @@
package org.springframework.transaction.aspectj;
-import java.lang.reflect.Method;
-
import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
@@ -25,7 +23,7 @@ import org.springframework.transaction.interceptor.TransactionAttributeSource;
/**
* Abstract superaspect for AspectJ transaction aspects. Concrete
- * subaspects will implement the transactionalMethodExecution()
+ * subaspects will implement the {@code transactionalMethodExecution()}
* pointcut using a strategy such as Java 5 annotations.
*
*
Suitable for use inside or outside the Spring IoC container.
@@ -42,45 +40,42 @@ import org.springframework.transaction.interceptor.TransactionAttributeSource;
*
* @author Rod Johnson
* @author Ramnivas Laddad
+ * @author Juergen Hoeller
* @since 2.0
*/
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
/**
- * Construct object using the given transaction metadata retrieval strategy.
+ * Construct the aspect using the given transaction metadata retrieval strategy.
* @param tas TransactionAttributeSource implementation, retrieving Spring
- * transaction metadata for each joinpoint. Write the subclass to pass in null
- * if it's intended to be configured by Setter Injection.
+ * transaction metadata for each joinpoint. Implement the subclass to pass in
+ * {@code null} if it is intended to be configured through Setter Injection.
*/
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
setTransactionAttributeSource(tas);
}
@SuppressAjWarnings("adviceDidNotMatch")
- before(Object txObject) : transactionalMethodExecution(txObject) {
+ Object around(final Object txObject): transactionalMethodExecution(txObject) {
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
- Method method = methodSignature.getMethod();
- createTransactionIfNecessary(method, txObject.getClass());
- }
-
- @SuppressAjWarnings("adviceDidNotMatch")
- after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
+ // Adapt to TransactionAspectSupport's invokeWithinTransaction...
try {
- completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
+ return invokeWithinTransaction(methodSignature.getMethod(), txObject.getClass(), new InvocationCallback() {
+ public Object proceedWithInvocation() throws Throwable {
+ return proceed(txObject);
+ }
+ });
}
- catch (Throwable t2) {
- logger.error("Failed to close transaction after throwing in a transactional method", t2);
+ catch (RuntimeException ex) {
+ throw ex;
+ }
+ catch (Error err) {
+ throw err;
+ }
+ catch (Throwable thr) {
+ Rethrower.rethrow(thr);
+ throw new IllegalStateException("Should never get here", thr);
}
- }
-
- @SuppressAjWarnings("adviceDidNotMatch")
- after(Object txObject) returning() : transactionalMethodExecution(txObject) {
- commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
- }
-
- @SuppressAjWarnings("adviceDidNotMatch")
- after(Object txObject) : transactionalMethodExecution(txObject) {
- cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
}
/**
@@ -90,4 +85,22 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor
*/
protected abstract pointcut transactionalMethodExecution(Object txObject);
+
+ /**
+ * Ugly but safe workaround: We need to be able to propagate checked exceptions,
+ * despite AspectJ around advice supporting specifically declared exceptions only.
+ */
+ private static class Rethrower {
+
+ public static void rethrow(final Throwable exception) {
+ class CheckedExceptionRethrower {
+ @SuppressWarnings("unchecked")
+ private void rethrow(Throwable exception) throws T {
+ throw (T) exception;
+ }
+ }
+ new CheckedExceptionRethrower().rethrow(exception);
+ }
+ }
+
}
diff --git a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AnnotationTransactionAspect.aj b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AnnotationTransactionAspect.aj
index 2ea8f9e3f584..70a82b5f4eef 100644
--- a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AnnotationTransactionAspect.aj
+++ b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AnnotationTransactionAspect.aj
@@ -21,17 +21,17 @@ import org.springframework.transaction.annotation.Transactional;
/**
* Concrete AspectJ transaction aspect using Spring's @Transactional annotation.
- *
+ *
*
When using this aspect, you must annotate the implementation class
* (and/or methods within that class), not the interface (if any) that
- * the class implements. AspectJ follows Java's rule that annotations on
+ * the class implements. AspectJ follows Java's rule that annotations on
* interfaces are not inherited.
*
*
An @Transactional annotation on a class specifies the default transaction
* semantics for the execution of any public operation in the class.
*
*
An @Transactional annotation on a method within the class overrides the
- * default transaction semantics given by the class annotation (if present).
+ * default transaction semantics given by the class annotation (if present).
* Any method may be annotated (regardless of visibility).
* Annotating non-public methods directly is the only way
* to get transaction demarcation for the execution of such operations.
@@ -49,16 +49,14 @@ public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
}
/**
- * Matches the execution of any public method in a type with the
- * Transactional annotation, or any subtype of a type with the
- * Transactional annotation.
+ * Matches the execution of any public method in a type with the Transactional
+ * annotation, or any subtype of a type with the Transactional annotation.
*/
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);
/**
- * Matches the execution of any method with the
- * Transactional annotation.
+ * Matches the execution of any method with the Transactional annotation.
*/
private pointcut executionOfTransactionalMethod() :
execution(@Transactional * *(..));
@@ -66,7 +64,7 @@ public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
/**
* Definition of pointcut from super aspect - matched join points
* will have Spring transaction management applied.
- */
+ */
protected pointcut transactionalMethodExecution(Object txObject) :
(executionOfAnyPublicMethodInAtTransactionalType()
|| executionOfTransactionalMethod() )
diff --git a/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java b/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java
index 70892e39493d..b69e861933ac 100644
--- a/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java
+++ b/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java
@@ -16,19 +16,18 @@
package org.springframework.transaction.aspectj;
-import java.lang.reflect.Method;
-
-import junit.framework.AssertionFailedError;
-
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import org.springframework.tests.transaction.CallCountingTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.interceptor.TransactionAttribute;
+import java.lang.reflect.Method;
+
/**
* @author Rod Johnson
* @author Ramnivas Laddad
+ * @author Juergen Hoeller
*/
public class TransactionAspectTests extends AbstractDependencyInjectionSpringContextTests {
@@ -123,50 +122,63 @@ public void testNotTransactional() throws Throwable {
public void testDefaultCommitOnAnnotatedClass() throws Throwable {
- testRollback(new TransactionOperationCallback() {
- public Object performTransactionalOperation() throws Throwable {
- return annotationOnlyOnClassWithNoInterface.echo(new Exception());
- }
- }, false);
+ final Exception ex = new Exception();
+ try {
+ testRollback(new TransactionOperationCallback() {
+ public Object performTransactionalOperation() throws Throwable {
+ return annotationOnlyOnClassWithNoInterface.echo(ex);
+ }
+ }, false);
+ fail("Should have thrown Exception");
+ }
+ catch (Exception ex2) {
+ assertSame(ex, ex2);
+ }
}
public void testDefaultRollbackOnAnnotatedClass() throws Throwable {
- testRollback(new TransactionOperationCallback() {
- public Object performTransactionalOperation() throws Throwable {
- return annotationOnlyOnClassWithNoInterface.echo(new RuntimeException());
- }
- }, true);
+ final RuntimeException ex = new RuntimeException();
+ try {
+ testRollback(new TransactionOperationCallback() {
+ public Object performTransactionalOperation() throws Throwable {
+ return annotationOnlyOnClassWithNoInterface.echo(ex);
+ }
+ }, true);
+ fail("Should have thrown RuntimeException");
+ }
+ catch (RuntimeException ex2) {
+ assertSame(ex, ex2);
+ }
}
- public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
- }
-
public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
- testRollback(new TransactionOperationCallback() {
- public Object performTransactionalOperation() throws Throwable {
- return new SubclassOfClassWithTransactionalAnnotation().echo(new Exception());
- }
- }, false);
- }
-
- public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
+ final Exception ex = new Exception();
+ try {
+ testRollback(new TransactionOperationCallback() {
+ public Object performTransactionalOperation() throws Throwable {
+ return new SubclassOfClassWithTransactionalAnnotation().echo(ex);
+ }
+ }, false);
+ fail("Should have thrown Exception");
+ }
+ catch (Exception ex2) {
+ assertSame(ex, ex2);
+ }
}
public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
- testRollback(new TransactionOperationCallback() {
- public Object performTransactionalOperation() throws Throwable {
- return new SubclassOfClassWithTransactionalMethodAnnotation().echo(new Exception());
- }
- }, false);
- }
-
- public static class ImplementsAnnotatedInterface implements ITransactional {
- public Object echo(Throwable t) throws Throwable {
- if (t != null) {
- throw t;
- }
- return t;
+ final Exception ex = new Exception();
+ try {
+ testRollback(new TransactionOperationCallback() {
+ public Object performTransactionalOperation() throws Throwable {
+ return new SubclassOfClassWithTransactionalMethodAnnotation().echo(ex);
+ }
+ }, false);
+ fail("Should have thrown Exception");
+ }
+ catch (Exception ex2) {
+ assertSame(ex, ex2);
}
}
@@ -221,18 +233,12 @@ protected void testRollback(TransactionOperationCallback toc, boolean rollback)
assertEquals(0, txManager.begun);
try {
toc.performTransactionalOperation();
- assertEquals(1, txManager.commits);
- }
- catch (Throwable caught) {
- if (caught instanceof AssertionFailedError) {
- return;
- }
}
-
- if (rollback) {
- assertEquals(1, txManager.rollbacks);
+ finally {
+ assertEquals(1, txManager.begun);
+ assertEquals(rollback ? 0 : 1, txManager.commits);
+ assertEquals(rollback ? 1 : 0, txManager.rollbacks);
}
- assertEquals(1, txManager.begun);
}
protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable {
@@ -258,4 +264,23 @@ private interface TransactionOperationCallback {
Object performTransactionalOperation() throws Throwable;
}
+
+ public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
+ }
+
+
+ public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
+ }
+
+
+ public static class ImplementsAnnotatedInterface implements ITransactional {
+
+ public Object echo(Throwable t) throws Throwable {
+ if (t != null) {
+ throw t;
+ }
+ return t;
+ }
+ }
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
index 9d11eeb520c7..09faf0c3b256 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
@@ -572,29 +572,30 @@ else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
}
@Override
- protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) {
- Class beanClass;
- if (mbd.getFactoryMethodName() != null) {
- beanClass = getTypeForFactoryMethod(beanName, mbd, typesToMatch);
- }
- else {
- beanClass = resolveBeanClass(mbd, beanName, typesToMatch);
+ protected Class> predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) {
+ Class> targetType = mbd.getTargetType();
+ if (targetType == null) {
+ targetType = (mbd.getFactoryMethodName() != null ? getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
+ resolveBeanClass(mbd, beanName, typesToMatch));
+ if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) {
+ mbd.setTargetType(targetType);
+ }
}
// Apply SmartInstantiationAwareBeanPostProcessors to predict the
// eventual type after a before-instantiation shortcut.
- if (beanClass != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
+ if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
- Class predictedType = ibp.predictBeanType(beanClass, beanName);
- if (predictedType != null && (typesToMatch.length > 1 ||
- !FactoryBean.class.equals(typesToMatch[0]) || FactoryBean.class.isAssignableFrom(predictedType))) {
- return predictedType;
+ Class predicted = ibp.predictBeanType(targetType, beanName);
+ if (predicted != null && (typesToMatch.length != 1 || !FactoryBean.class.equals(typesToMatch[0]) ||
+ FactoryBean.class.isAssignableFrom(predicted))) {
+ return predicted;
}
}
}
}
- return beanClass;
+ return targetType;
}
/**
@@ -611,8 +612,8 @@ protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class..
* @return the type for the bean if determinable, or {@code null} else
* @see #createBean
*/
- protected Class getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class[] typesToMatch) {
- Class factoryClass;
+ protected Class> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class[] typesToMatch) {
+ Class> factoryClass;
boolean isStatic = true;
String factoryBeanName = mbd.getFactoryBeanName();
@@ -686,7 +687,7 @@ class Holder { Class> value = null; }
if (factoryBeanName != null && factoryMethodName != null) {
// Try to obtain the FactoryBean's object type without instantiating it at all.
BeanDefinition fbDef = getBeanDefinition(factoryBeanName);
- if (fbDef instanceof AbstractBeanDefinition) {
+ if (fbDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) fbDef).hasBeanClass()) {
Class> fbClass = ((AbstractBeanDefinition) fbDef).getBeanClass();
if (ClassUtils.isCglibProxyClass(fbClass)) {
// CGLIB subclass methods hide generic parameters. look at the superclass.
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java
index 7b7822f0df0e..d51dc55fa723 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -165,7 +165,7 @@ public PropertiesBeanDefinitionReader(BeanDefinitionRegistry registry) {
* class can still override this.
*
Strictly speaking, the rule that a default parent setting does
* not apply to a bean definition that carries a class is there for
- * backwards compatiblity reasons. It still matches the typical use case.
+ * backwards compatibility reasons. It still matches the typical use case.
*/
public void setDefaultParentBean(String defaultParentBean) {
this.defaultParentBean = defaultParentBean;
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
index 7eaba17a5468..64d0555d4913 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -61,8 +61,12 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
boolean allowCaching = true;
+ private volatile Class> targetType;
+
boolean isFactoryMethodUnique = false;
+ final Object constructorArgumentLock = new Object();
+
/** Package-visible field for caching the resolved constructor or factory method */
Object resolvedConstructorOrFactoryMethod;
@@ -75,15 +79,13 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
/** Package-visible field for caching partly prepared constructor arguments */
Object[] preparedConstructorArguments;
- final Object constructorArgumentLock = new Object();
-
- /** Package-visible field that indicates a before-instantiation post-processor having kicked in */
- volatile Boolean beforeInstantiationResolved;
+ final Object postProcessingLock = new Object();
/** Package-visible field that indicates MergedBeanDefinitionPostProcessor having been applied */
boolean postProcessed = false;
- final Object postProcessingLock = new Object();
+ /** Package-visible field that indicates a before-instantiation post-processor having kicked in */
+ volatile Boolean beforeInstantiationResolved;
/**
@@ -236,6 +238,8 @@ public RootBeanDefinition(RootBeanDefinition original) {
if (original instanceof RootBeanDefinition) {
RootBeanDefinition originalRbd = (RootBeanDefinition) original;
this.decoratedDefinition = originalRbd.decoratedDefinition;
+ this.allowCaching = originalRbd.allowCaching;
+ this.targetType = originalRbd.targetType;
this.isFactoryMethodUnique = originalRbd.isFactoryMethodUnique;
}
}
@@ -251,6 +255,21 @@ public void setParentName(String parentName) {
}
}
+ /**
+ * Specify the target type of this bean definition, if known in advance.
+ */
+ public void setTargetType(Class> targetType) {
+ this.targetType = targetType;
+ }
+
+ /**
+ * Return the target type of this bean definition, if known
+ * (either specified in advance or resolved on first instantiation).
+ */
+ public Class> getTargetType() {
+ return this.targetType;
+ }
+
/**
* Specify a factory method name that refers to a non-overloaded method.
*/
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanConfigurerSupport.java b/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanConfigurerSupport.java
index 3413b457c061..81fa4242b2f6 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanConfigurerSupport.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanConfigurerSupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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,14 +30,13 @@
import org.springframework.util.ClassUtils;
/**
- * Convenient base class for configurers that can perform Dependency Injection
+ * Convenient base class for bean configurers that can perform Dependency Injection
* on objects (however they may be created). Typically subclassed by AspectJ aspects.
*
*
Subclasses may also need a custom metadata resolution strategy, in the
- * {@link BeanWiringInfoResolver} interface. The default implementation looks
- * for a bean with the same name as the fully-qualified class name. (This is
- * the default name of the bean in a Spring XML file if the '{@code id}'
- * attribute is not used.)
+ * {@link BeanWiringInfoResolver} interface. The default implementation looks for
+ * a bean with the same name as the fully-qualified class name. (This is the default
+ * name of the bean in a Spring XML file if the '{@code id}' attribute is not used.)
* @author Rob Harrop
* @author Rod Johnson
@@ -113,8 +112,7 @@ public void destroy() {
/**
* Configure the bean instance.
*
Subclasses can override this to provide custom configuration logic.
- * Typically called by an aspect, for all bean instances matched by a
- * pointcut.
+ * Typically called by an aspect, for all bean instances matched by a pointcut.
* @param beanInstance the bean instance to configure (must not be {@code null})
*/
public void configureBean(Object beanInstance) {
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
index 4045578c8c44..94f6376ce18f 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
@@ -591,7 +591,6 @@ public void testPossibleMatches() {
fail("Should throw exception on invalid property");
}
catch (BeanCreationException ex) {
- ex.printStackTrace();
assertTrue(ex.getCause() instanceof NotWritablePropertyException);
NotWritablePropertyException cause = (NotWritablePropertyException) ex.getCause();
// expected
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java
index cc009917fd36..550e87375b23 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/parsing/CustomProblemReporterTests.java
@@ -29,7 +29,6 @@
import org.springframework.core.io.Resource;
import org.springframework.tests.sample.beans.TestBean;
-
/**
* @author Rob Harrop
* @author Chris Beams
@@ -78,7 +77,6 @@ public void fatal(Problem problem) {
@Override
public void error(Problem problem) {
- System.out.println(problem);
this.errors.add(problem);
}
@@ -88,7 +86,6 @@ public Problem[] getErrors() {
@Override
public void warning(Problem problem) {
- System.out.println(problem);
this.warnings.add(problem);
}
}
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java
index c8c6595e455a..d0439fa93eff 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java
@@ -16,12 +16,6 @@
package org.springframework.beans.factory.support.security;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
import java.lang.reflect.Method;
import java.net.URL;
import java.security.AccessControlContext;
@@ -39,8 +33,8 @@
import javax.security.auth.Subject;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
+
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanCreationException;
@@ -60,6 +54,8 @@
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
+import static org.junit.Assert.*;
+
/**
* Security test case. Checks whether the container uses its privileges for its
* internal work but does not leak them when touching/calling user code.
@@ -456,9 +452,6 @@ public void testConstructor() throws Exception {
}
@Test
- @Ignore("passes under Eclipse, but fails under Gradle with https://gist.github.com/1664133")
- // TODO [SPR-10074] passes under Eclipse, but fails under Gradle with
- // https://gist.github.com/1664133
public void testContainerPrivileges() throws Exception {
AccessControlContext acc = provider.getAccessControlContext();
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java
index 0b65929fdd31..a68028c5921d 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.beans.factory.support.security.support;
/**
@@ -25,6 +26,5 @@ public ConstructorBean() {
}
public ConstructorBean(Object obj) {
- System.out.println("Received object " + obj);
}
}
diff --git a/spring-beans/src/test/resources/log4j.xml b/spring-beans/src/test/resources/log4j.xml
index 37f573d2aef2..6f012e992400 100644
--- a/spring-beans/src/test/resources/log4j.xml
+++ b/spring-beans/src/test/resources/log4j.xml
@@ -11,21 +11,13 @@
-
-
-
-
-
-
-
-
-
+
-
+
diff --git a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheFactoryBean.java b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheFactoryBean.java
index fc2ad0002229..dcec4047eeec 100644
--- a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheFactoryBean.java
+++ b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -40,9 +40,9 @@
import org.springframework.util.Assert;
/**
- * {@link FactoryBean} that creates a named EHCache {@link net.sf.ehcache.Cache} instance
+ * {@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}.
+ * representing a cache region within an EhCache {@link net.sf.ehcache.CacheManager}.
*
*
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
@@ -52,7 +52,8 @@
*
Note: If the named Cache instance is found, the properties will be ignored and the
* Cache instance will be retrieved from the CacheManager.
*
- *
Note: As of Spring 3.0, Spring's EHCache support requires EHCache 1.3 or higher.
+ *
Note: As of Spring 3.0, Spring's EhCache support requires EhCache 1.3 or higher.
+ * As of Spring 3.2, we recommend using EhCache 2.1 or higher.
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
@@ -117,7 +118,7 @@ public class EhCacheFactoryBean implements FactoryBean, BeanNameAware,
* properly handle the shutdown of the CacheManager: Set up a separate
* EhCacheManagerFactoryBean and pass a reference to this bean property.
*
A separate EhCacheManagerFactoryBean is also necessary for loading
- * EHCache configuration from a non-default config location.
+ * EhCache configuration from a non-default config location.
* @see EhCacheManagerFactoryBean
* @see net.sf.ehcache.CacheManager#getInstance
*/
@@ -152,7 +153,7 @@ public void setMaxElementsOnDisk(int maxElementsOnDisk) {
/**
* Set the memory style eviction policy for this cache.
*
Supported values are "LRU", "LFU" and "FIFO", according to the
- * constants defined in EHCache's MemoryStoreEvictionPolicy class.
+ * constants defined in EhCache's MemoryStoreEvictionPolicy class.
* Default is "LRU".
*/
public void setMemoryStoreEvictionPolicy(MemoryStoreEvictionPolicy memoryStoreEvictionPolicy) {
@@ -239,9 +240,9 @@ public void setBlocking(boolean blocking) {
}
/**
- * Set an EHCache {@link net.sf.ehcache.constructs.blocking.CacheEntryFactory}
+ * 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
+ * the cache will be decorated with EhCache's
* {@link net.sf.ehcache.constructs.blocking.SelfPopulatingCache}.
*
The specified factory can be of type
* {@link net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory},
@@ -257,7 +258,7 @@ public void setCacheEntryFactory(CacheEntryFactory cacheEntryFactory) {
}
/**
- * Set an EHCache {@link net.sf.ehcache.bootstrap.BootstrapCacheLoader}
+ * Set an EhCache {@link net.sf.ehcache.bootstrap.BootstrapCacheLoader}
* for this cache, if any.
*/
public void setBootstrapCacheLoader(BootstrapCacheLoader bootstrapCacheLoader) {
@@ -265,7 +266,7 @@ public void setBootstrapCacheLoader(BootstrapCacheLoader bootstrapCacheLoader) {
}
/**
- * Specify EHCache {@link net.sf.ehcache.event.CacheEventListener cache event listeners}
+ * Specify EhCache {@link net.sf.ehcache.event.CacheEventListener cache event listeners}
* to registered with this cache.
*/
public void setCacheEventListeners(Set cacheEventListeners) {
@@ -305,7 +306,7 @@ public void afterPropertiesSet() throws CacheException, IOException {
// If no CacheManager given, fetch the default.
if (this.cacheManager == null) {
if (logger.isDebugEnabled()) {
- logger.debug("Using default EHCache CacheManager for cache region '" + this.cacheName + "'");
+ logger.debug("Using default EhCache CacheManager for cache region '" + this.cacheName + "'");
}
this.cacheManager = CacheManager.getInstance();
}
@@ -320,13 +321,13 @@ public void afterPropertiesSet() throws CacheException, IOException {
Ehcache rawCache;
if (this.cacheManager.cacheExists(this.cacheName)) {
if (logger.isDebugEnabled()) {
- logger.debug("Using existing EHCache cache region '" + this.cacheName + "'");
+ logger.debug("Using existing EhCache cache region '" + this.cacheName + "'");
}
rawCache = this.cacheManager.getEhcache(this.cacheName);
}
else {
if (logger.isDebugEnabled()) {
- logger.debug("Creating new EHCache cache region '" + this.cacheName + "'");
+ logger.debug("Creating new EhCache cache region '" + this.cacheName + "'");
}
rawCache = createCache();
this.cacheManager.addCache(rawCache);
@@ -359,7 +360,7 @@ public void afterPropertiesSet() throws CacheException, IOException {
* Create a raw Cache object based on the configuration of this FactoryBean.
*/
protected Cache createCache() {
- // Only call EHCache 1.6 constructor if actually necessary (for compatibility with EHCache 1.3+)
+ // Only call EhCache 1.6 constructor if actually necessary (for compatibility with EhCache 1.3+)
return (!this.clearOnFlush) ?
new Cache(this.cacheName, this.maxElementsInMemory, this.memoryStoreEvictionPolicy,
this.overflowToDisk, null, this.eternal, this.timeToLive, this.timeToIdle,
diff --git a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java
index a170eb84f85d..a94c1fe2cb17 100644
--- a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java
+++ b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java
@@ -35,19 +35,20 @@
import org.springframework.util.ReflectionUtils;
/**
- * {@link FactoryBean} that exposes an EHCache {@link net.sf.ehcache.CacheManager}
+ * {@link FactoryBean} that exposes an EhCache {@link net.sf.ehcache.CacheManager}
* instance (independent or shared), configured from a specified config location.
*
*
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).
+ * "ehcache.xml" in the root of the class path (that is, default EhCache initialization
+ * - as defined in the EhCache docs - will apply).
*
*
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.
+ * also necessary for loading EhCache configuration from a non-default config location.
*
- *
Note: As of Spring 3.0, Spring's EHCache support requires EHCache 1.3 or higher.
+ *
Note: As of Spring 3.0, Spring's EhCache support requires EhCache 1.3 or higher.
+ * As of Spring 3.2, we recommend using EhCache 2.1 or higher.
*
* @author Dmitriy Kopylenko
* @author Juergen Hoeller
@@ -59,7 +60,7 @@
*/
public class EhCacheManagerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
- // Check whether EHCache 2.1+ CacheManager.create(Configuration) method is available...
+ // Check whether EhCache 2.1+ CacheManager.create(Configuration) method is available...
private static final Method createWithConfiguration =
ClassUtils.getMethodIfAvailable(CacheManager.class, "create", Configuration.class);
@@ -75,9 +76,9 @@ public class EhCacheManagerFactoryBean implements FactoryBean, Ini
/**
- * Set the location of the EHCache config file. A typical value is "/WEB-INF/ehcache.xml".
+ * Set the location of the EhCache config file. A typical value is "/WEB-INF/ehcache.xml".
*
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).
+ * "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)
*/
@@ -86,7 +87,7 @@ public void setConfigLocation(Resource configLocation) {
}
/**
- * Set whether the EHCache CacheManager should be shared (as a singleton at the VM level)
+ * Set whether the EhCache CacheManager should be shared (as a singleton at the VM level)
* or independent (typically local within the application). Default is "false", creating
* an independent instance.
* @see net.sf.ehcache.CacheManager#create()
@@ -97,7 +98,7 @@ public void setShared(boolean shared) {
}
/**
- * Set the name of the EHCache CacheManager (if a specific name is desired).
+ * Set the name of the EhCache CacheManager (if a specific name is desired).
* @see net.sf.ehcache.CacheManager#setName(String)
*/
public void setCacheManagerName(String cacheManagerName) {
@@ -106,14 +107,14 @@ public void setCacheManagerName(String cacheManagerName) {
public void afterPropertiesSet() throws IOException, CacheException {
- logger.info("Initializing EHCache CacheManager");
+ logger.info("Initializing EhCache CacheManager");
InputStream is = (this.configLocation != null ? this.configLocation.getInputStream() : null);
try {
- // A bit convoluted for EHCache 1.x/2.0 compatibility.
- // To be much simpler once we require EHCache 2.1+
+ // A bit convoluted for EhCache 1.x/2.0 compatibility.
+ // To be much simpler once we require EhCache 2.1+
if (this.cacheManagerName != null) {
if (this.shared && createWithConfiguration == null) {
- // No CacheManager.create(Configuration) method available before EHCache 2.1;
+ // No CacheManager.create(Configuration) method available before EhCache 2.1;
// can only set CacheManager name after creation.
this.cacheManager = (is != null ? CacheManager.create(is) : CacheManager.create());
this.cacheManager.setName(this.cacheManagerName);
@@ -160,7 +161,7 @@ public boolean isSingleton() {
public void destroy() {
- logger.info("Shutting down EHCache CacheManager");
+ logger.info("Shutting down EhCache CacheManager");
this.cacheManager.shutdown();
}
diff --git a/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheSupportTests.java b/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheSupportTests.java
index fcfe22164250..6e8efcd81656 100644
--- a/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheSupportTests.java
+++ b/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheSupportTests.java
@@ -133,7 +133,6 @@ private void doTestEhCacheFactoryBean(boolean useCacheManagerFb) throws Exceptio
cacheFb.setBeanName("undefinedCache2");
cacheFb.setMaxElementsInMemory(5);
cacheFb.setOverflowToDisk(false);
- cacheFb.setEternal(true);
cacheFb.setTimeToLive(8);
cacheFb.setTimeToIdle(7);
cacheFb.setDiskPersistent(true);
@@ -145,7 +144,6 @@ private void doTestEhCacheFactoryBean(boolean useCacheManagerFb) throws Exceptio
assertEquals("undefinedCache2", cache.getName());
assertTrue("overridden maxElements is correct", config.getMaxElementsInMemory() == 5);
assertFalse("overridden overflowToDisk is correct", config.isOverflowToDisk());
- assertTrue("overridden eternal is correct", config.isEternal());
assertTrue("default timeToLive is correct", config.getTimeToLiveSeconds() == 8);
assertTrue("default timeToIdle is correct", config.getTimeToIdleSeconds() == 7);
assertTrue("overridden diskPersistent is correct", config.isDiskPersistent());
diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/Caching.java b/spring-context/src/main/java/org/springframework/cache/annotation/Caching.java
index 7d3e77d3192c..6bad879b76f8 100644
--- a/spring-context/src/main/java/org/springframework/cache/annotation/Caching.java
+++ b/spring-context/src/main/java/org/springframework/cache/annotation/Caching.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,7 @@
package org.springframework.cache.annotation;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
/**
* Group annotation for multiple cache annotations (of different or the same type).
@@ -30,7 +25,7 @@
* @author Chris Beams
* @since 3.1
*/
-@Target({ ElementType.METHOD, ElementType.TYPE })
+@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@@ -41,4 +36,5 @@
CachePut[] put() default {};
CacheEvict[] evict() default {};
+
}
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/Bean.java b/spring-context/src/main/java/org/springframework/context/annotation/Bean.java
index a0c8ab11593a..679352decf1c 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/Bean.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/Bean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -177,7 +177,7 @@
* @see org.springframework.beans.factory.annotation.Autowired
* @see org.springframework.beans.factory.annotation.Value
*/
-@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@@ -190,7 +190,7 @@
String[] name() default {};
/**
- * Are dependencies to be injected via autowiring?
+ * Are dependencies to be injected via convention-based autowiring by name or type?
*/
Autowire autowire() default Autowire.NO;
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java
index 99678159d336..37c74ce2a1fb 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java
@@ -17,17 +17,11 @@
package org.springframework.context.annotation;
import java.lang.reflect.Method;
+import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.springframework.cglib.proxy.Callback;
-import org.springframework.cglib.proxy.CallbackFilter;
-import org.springframework.cglib.proxy.Enhancer;
-import org.springframework.cglib.proxy.MethodInterceptor;
-import org.springframework.cglib.proxy.MethodProxy;
-import org.springframework.cglib.proxy.NoOp;
-
import org.springframework.aop.scope.ScopedProxyFactoryBean;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.DisposableBean;
@@ -35,6 +29,12 @@
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.SimpleInstantiationStrategy;
+import org.springframework.cglib.proxy.Callback;
+import org.springframework.cglib.proxy.CallbackFilter;
+import org.springframework.cglib.proxy.Enhancer;
+import org.springframework.cglib.proxy.MethodInterceptor;
+import org.springframework.cglib.proxy.MethodProxy;
+import org.springframework.cglib.proxy.NoOp;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
@@ -52,8 +52,8 @@ class ConfigurationClassEnhancer {
private static final Log logger = LogFactory.getLog(ConfigurationClassEnhancer.class);
- private static final Class>[] CALLBACK_TYPES = { BeanMethodInterceptor.class,
- DisposableBeanMethodInterceptor.class, NoOp.class };
+ private static final Class>[] CALLBACK_TYPES = {BeanMethodInterceptor.class,
+ DisposableBeanMethodInterceptor.class, NoOp.class};
private static final CallbackFilter CALLBACK_FILTER = new CallbackFilter() {
public int accept(Method candidateMethod) {
@@ -80,10 +80,8 @@ public int accept(Method candidateMethod) {
public ConfigurationClassEnhancer(ConfigurableBeanFactory beanFactory) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
// Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER
- this.callbackInstances = new Callback[] {
- new BeanMethodInterceptor(beanFactory),
- DISPOSABLE_BEAN_METHOD_INTERCEPTOR,
- NoOp.INSTANCE };
+ this.callbackInstances = new Callback[]
+ {new BeanMethodInterceptor(beanFactory), DISPOSABLE_BEAN_METHOD_INTERCEPTOR, NoOp.INSTANCE};
}
/**
@@ -169,9 +167,8 @@ public GetObjectMethodInterceptor(ConfigurableBeanFactory beanFactory, String be
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
- return beanFactory.getBean(beanName);
+ return this.beanFactory.getBean(this.beanName);
}
-
}
@@ -209,19 +206,16 @@ public static boolean isDestroyMethod(Method candidateMethod) {
*/
private static class BeanMethodInterceptor implements MethodInterceptor {
- private static final Class>[] CALLBACK_TYPES = {
- GetObjectMethodInterceptor.class, NoOp.class };
+ private static final Class>[] CALLBACK_TYPES = {GetObjectMethodInterceptor.class, NoOp.class};
- private static final CallbackFilter CALLBACK_FITLER = new CallbackFilter() {
+ private static final CallbackFilter CALLBACK_FILTER = new CallbackFilter() {
public int accept(Method method) {
- return method.getName().equals("getObject") ? 0 : 1;
+ return (method.getName().equals("getObject") ? 0 : 1);
}
};
-
private final ConfigurableBeanFactory beanFactory;
-
public BeanMethodInterceptor(ConfigurableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@@ -229,7 +223,6 @@ public BeanMethodInterceptor(ConfigurableBeanFactory beanFactory) {
/**
* Enhance a {@link Bean @Bean} method to check the supplied BeanFactory for the
* existence of this bean object.
- *
* @throws Throwable as a catch-all for any exception that may be thrown when
* invoking the super implementation of the proxied method i.e., the actual
* {@code @Bean} method.
@@ -255,8 +248,8 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// this ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
- if (factoryContainsBean('&'+beanName) && factoryContainsBean(beanName)) {
- Object factoryBean = this.beanFactory.getBean('&'+beanName);
+ if (factoryContainsBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName) && factoryContainsBean(beanName)) {
+ Object factoryBean = this.beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// pass through - scoped proxy factory beans are a special case and should not
// be further proxied
@@ -267,9 +260,7 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
}
}
- boolean factoryIsCaller = beanMethod.equals(SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod());
- boolean factoryAlreadyContainsSingleton = this.beanFactory.containsSingleton(beanName);
- if (factoryIsCaller && !factoryAlreadyContainsSingleton) {
+ if (isCurrentlyInvokedFactoryMethod(beanMethod) && !this.beanFactory.containsSingleton(beanName)) {
// the factory is calling the bean method in order to instantiate and register the bean
// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
// create the bean instance.
@@ -306,7 +297,7 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
}
/**
- * Check the beanFactory to see whether the bean named beanName already
+ * Check the BeanFactory to see whether the bean named beanName already
* exists. Accounts for the fact that the requested bean may be "in creation", i.e.:
* we're in the middle of servicing the initial request for this bean. From an enhanced
* factory method's perspective, this means that the bean does not actually yet exist,
@@ -319,9 +310,19 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
* @return whether beanName already exists in the factory
*/
private boolean factoryContainsBean(String beanName) {
- boolean containsBean = this.beanFactory.containsBean(beanName);
- boolean currentlyInCreation = this.beanFactory.isCurrentlyInCreation(beanName);
- return (containsBean && !currentlyInCreation);
+ return (this.beanFactory.containsBean(beanName) && !this.beanFactory.isCurrentlyInCreation(beanName));
+ }
+
+ /**
+ * Check whether the given method corresponds to the container's currently invoked
+ * factory method. Compares method name and parameter types only in order to work
+ * around a potential problem with covariant return types (currently only known
+ * to happen on Groovy classes).
+ */
+ private boolean isCurrentlyInvokedFactoryMethod(Method method) {
+ Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
+ return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
+ Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}
/**
@@ -335,13 +336,12 @@ private Object enhanceFactoryBean(Class> fbClass, String beanName) throws Inst
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(fbClass);
enhancer.setUseFactory(false);
- enhancer.setCallbackFilter(CALLBACK_FITLER);
+ enhancer.setCallbackFilter(CALLBACK_FILTER);
// Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER
Callback[] callbackInstances = new Callback[] {
new GetObjectMethodInterceptor(this.beanFactory, beanName),
NoOp.INSTANCE
};
-
enhancer.setCallbackTypes(CALLBACK_TYPES);
Class> fbSubclass = enhancer.createClass();
Enhancer.registerCallbacks(fbSubclass, callbackInstances);
diff --git a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java
index aedf1184373a..b74b53262b5b 100644
--- a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java
+++ b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java
@@ -40,20 +40,24 @@
public class DateFormatterRegistrar implements FormatterRegistrar {
- private DateFormatter dateFormatter = new DateFormatter();
+ private DateFormatter dateFormatter;
public void registerFormatters(FormatterRegistry registry) {
addDateConverters(registry);
- registry.addFormatter(dateFormatter);
- registry.addFormatterForFieldType(Calendar.class, dateFormatter);
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
+
+ // In order to retain back compatibility we only register Date/Calendar
+ // types when a user defined formatter is specified (see SPR-10105)
+ if(this.dateFormatter != null) {
+ registry.addFormatter(this.dateFormatter);
+ registry.addFormatterForFieldType(Calendar.class, this.dateFormatter);
+ }
}
/**
- * Set the date formatter to register. If not specified the default {@link DateFormatter}
- * will be used. This method can be used if additional formatter configuration is
- * required.
+ * Set the date formatter to register. If not specified no formatter is registered.
+ * This method can be used if global formatter configuration is required.
* @param dateFormatter the date formatter
*/
public void setFormatter(DateFormatter dateFormatter) {
@@ -117,7 +121,7 @@ private static class LongToCalendarConverter implements Converter asyncAnnotationTy
this.pointcut = buildPointcut(asyncAnnotationTypes);
}
+ /**
+ * Set the {@code BeanFactory} to be used when looking up executors by qualifier.
+ */
+ public void setBeanFactory(BeanFactory beanFactory) {
+ if (this.advice instanceof BeanFactoryAware) {
+ ((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
+ }
+ }
+
public Advice getAdvice() {
return this.advice;
diff --git a/spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java b/spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java
index 5f5cf4e28099..68d127c72f33 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java
@@ -71,7 +71,19 @@ public class CronSequenceGenerator {
/**
- * Construct a {@link CronSequenceGenerator} from the pattern provided.
+ * Construct a {@link CronSequenceGenerator} from the pattern provided,
+ * using the default {@link TimeZone}.
+ * @param expression a space-separated list of time fields
+ * @throws IllegalArgumentException if the pattern cannot be parsed
+ * @see java.util.TimeZone#getDefault()
+ */
+ public CronSequenceGenerator(String expression) {
+ this(expression, TimeZone.getDefault());
+ }
+
+ /**
+ * Construct a {@link CronSequenceGenerator} from the pattern provided,
+ * using the specified {@link TimeZone}.
* @param expression a space-separated list of time fields
* @param timeZone the TimeZone to use for generated trigger times
* @throws IllegalArgumentException if the pattern cannot be parsed
@@ -114,12 +126,17 @@ public Date next(Date date) {
calendar.setTimeZone(this.timeZone);
calendar.setTime(date);
- // Truncate to the next whole second
- calendar.add(Calendar.SECOND, 1);
+ // First, just reset the milliseconds and try to calculate from there...
calendar.set(Calendar.MILLISECOND, 0);
-
+ long originalTimestamp = calendar.getTimeInMillis();
doNext(calendar, calendar.get(Calendar.YEAR));
+ if (calendar.getTimeInMillis() == originalTimestamp) {
+ // We arrived at the original timestamp - round up to the next whole second and try again...
+ calendar.add(Calendar.SECOND, 1);
+ doNext(calendar, calendar.get(Calendar.YEAR));
+ }
+
return calendar.getTime();
}
diff --git a/spring-context/src/main/java/org/springframework/scheduling/support/CronTrigger.java b/spring-context/src/main/java/org/springframework/scheduling/support/CronTrigger.java
index eca37982e6d4..94f6385a1a9c 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/support/CronTrigger.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/support/CronTrigger.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,12 @@
package org.springframework.scheduling.support;
-import java.util.Date;
-import java.util.TimeZone;
-
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
+import java.util.Date;
+import java.util.TimeZone;
+
/**
* {@link Trigger} implementation for cron expressions.
* Wraps a {@link CronSequenceGenerator}.
@@ -41,7 +41,7 @@ public class CronTrigger implements Trigger {
* following cron expression conventions
*/
public CronTrigger(String cronExpression) {
- this(cronExpression, TimeZone.getDefault());
+ this.sequenceGenerator = new CronSequenceGenerator(cronExpression);
}
/**
@@ -89,7 +89,7 @@ public int hashCode() {
@Override
public String toString() {
- return sequenceGenerator.toString();
+ return this.sequenceGenerator.toString();
}
}
diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java
index 58cd161175be..3d4b907fa2fb 100644
--- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java
+++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -46,8 +46,8 @@
* of that class. By default, JSR-303 will validate against its default group only.
*
*
As of Spring 3.1, this functionality requires Hibernate Validator 4.2 or higher.
- * In Spring 3.1.2, this class will autodetect a Bean Validation 1.1 compliant provider
- * and automatically use the standard method validation support there (once available).
+ * Once Bean Validation 1.1 becomes available, this class will autodetect a compliant
+ * provider and automatically use the standard method validation support there.
*
* @author Juergen Hoeller
* @since 3.1
diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java
index 7565e82099cb..f3c45fc2fa2b 100644
--- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java
+++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java
@@ -130,7 +130,8 @@ protected void processConstraintViolations(Set> viol
}
else {
Object invalidValue = violation.getInvalidValue();
- if (field.contains(".") && !field.contains("[]")) {
+ if (!"".equals(field) && (invalidValue == violation.getLeafBean() ||
+ (field.contains(".") && !field.contains("[]")))) {
// Possibly a bean constraint with property path: retrieve the actual property value.
// However, explicitly avoid this for "address[]" style paths that we can't handle.
invalidValue = bindingResult.getRawFieldValue(field);
diff --git a/spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvalutatorTest.java b/spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvaluatorTests.java
similarity index 99%
rename from spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvalutatorTest.java
rename to spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvaluatorTests.java
index 0a664afac0ec..44762719bcf0 100644
--- a/spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvalutatorTest.java
+++ b/spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvaluatorTests.java
@@ -44,7 +44,7 @@
* @author Costin Leau
* @author Phillip Webb
*/
-public class ExpressionEvalutatorTest {
+public class ExpressionEvaluatorTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
diff --git a/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java b/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java
index 5698ed06518e..2803f0dc9f9d 100644
--- a/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java
+++ b/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java
@@ -16,7 +16,10 @@
package org.springframework.format.datetime;
+import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.Calendar;
@@ -50,9 +53,12 @@ public class DateFormattingTests {
@Before
public void setUp() {
- DefaultConversionService.addDefaultConverters(conversionService);
-
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
+ setUp(registrar);
+ }
+
+ private void setUp(DateFormatterRegistrar registrar) {
+ DefaultConversionService.addDefaultConverters(conversionService);
registrar.registerFormatters(conversionService);
SimpleDateBean bean = new SimpleDateBean();
@@ -187,13 +193,48 @@ public void testBindNestedDateAnnotated() {
}
@Test
- public void dateToString() throws Exception {
+ public void dateToStringWithoutGlobalFormat() throws Exception {
+ Date date = new Date();
+ Object actual = this.conversionService.convert(date, TypeDescriptor.valueOf(Date.class), TypeDescriptor.valueOf(String.class));
+ String expected = date.toString();
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void dateToStringWithGlobalFormat() throws Exception {
+ DateFormatterRegistrar registrar = new DateFormatterRegistrar();
+ registrar.setFormatter(new DateFormatter());
+ setUp(registrar);
Date date = new Date();
Object actual = this.conversionService.convert(date, TypeDescriptor.valueOf(Date.class), TypeDescriptor.valueOf(String.class));
String expected = new DateFormatter().print(date, Locale.US);
assertEquals(expected, actual);
}
+ @Test
+ @SuppressWarnings("deprecation")
+ public void stringToDateWithoutGlobalFormat() throws Exception {
+ // SPR-10105
+ String string = "Sat, 12 Aug 1995 13:30:00 GM";
+ Date date = this.conversionService.convert(string, Date.class);
+ assertThat(date, equalTo(new Date(string)));
+ }
+
+ @Test
+ public void stringToDateWithGlobalFormat() throws Exception {
+ // SPR-10105
+ DateFormatterRegistrar registrar = new DateFormatterRegistrar();
+ DateFormatter dateFormatter = new DateFormatter();
+ dateFormatter.setIso(ISO.DATE_TIME);
+ registrar.setFormatter(dateFormatter);
+ setUp(registrar);
+ // This is a format that cannot be parsed by new Date(String)
+ String string = "2009-06-01T14:23:05.003+0000";
+ Date date = this.conversionService.convert(string, Date.class);
+ assertNotNull(date);
+ }
+
+
@SuppressWarnings("unused")
private static class SimpleDateBean {
diff --git a/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java b/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java
index 237df0509f3f..c2aaf8d36a3c 100644
--- a/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java
+++ b/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java
@@ -16,6 +16,11 @@
package org.springframework.format.datetime.joda;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
@@ -32,7 +37,6 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-
import org.springframework.beans.MutablePropertyValues;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.convert.TypeDescriptor;
@@ -42,8 +46,6 @@
import org.springframework.format.support.FormattingConversionService;
import org.springframework.validation.DataBinder;
-import static org.junit.Assert.*;
-
/**
* @author Keith Donald
* @author Juergen Hoeller
@@ -459,13 +461,40 @@ public void testBindMutableDateTimeAnnotated() {
}
@Test
- public void dateToString() throws Exception {
+ public void dateToStringWithFormat() throws Exception {
+ JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
+ registrar.setDateTimeFormatter(org.joda.time.format.DateTimeFormat.shortDateTime());
+ setUp(registrar);
Date date = new Date();
Object actual = this.conversionService.convert(date, TypeDescriptor.valueOf(Date.class), TypeDescriptor.valueOf(String.class));
String expected = JodaTimeContextHolder.getFormatter(org.joda.time.format.DateTimeFormat.shortDateTime(), Locale.US).print(new DateTime(date));
assertEquals(expected, actual);
}
+ @Test
+ @SuppressWarnings("deprecation")
+ public void stringToDateWithoutGlobalFormat() throws Exception {
+ // SPR-10105
+ String string = "Sat, 12 Aug 1995 13:30:00 GM";
+ Date date = this.conversionService.convert(string, Date.class);
+ assertThat(date, equalTo(new Date(string)));
+ }
+
+ @Test
+ public void stringToDateWithGlobalFormat() throws Exception {
+ // SPR-10105
+ JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
+ DateTimeFormatterFactory factory = new DateTimeFormatterFactory();
+ factory.setIso(ISO.DATE_TIME);
+ registrar.setDateTimeFormatter(factory.createDateTimeFormatter());
+ setUp(registrar);
+ // This is a format that cannot be parsed by new Date(String)
+ String string = "2009-10-31T07:00:00.000-05:00";
+ Date date = this.conversionService.convert(string, Date.class);
+ assertNotNull(date);
+ }
+
+
@SuppressWarnings("unused")
private static class JodaTimeBean {
diff --git a/spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java b/spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java
index 12dbf05a50c3..ab05a3ea6ed0 100644
--- a/spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -20,32 +20,38 @@
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
-import junit.framework.TestCase;
-
+import org.junit.After;
+import org.junit.Before;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.tests.TestGroup;
import org.springframework.util.MBeanTestUtils;
+import static org.junit.Assert.*;
+
/**
- * Note: the JMX test suite requires the presence of the
- * {@code jmxremote_optional.jar} in your classpath. Thus, if you
- * run into the "Unsupported protocol: jmxmp" error, you will
- * need to download the
- * JMX Remote API 1.0.1_04 Reference Implementation
- * from Oracle and extract {@code jmxremote_optional.jar} into your
- * classpath, for example in the {@code lib/ext} folder of your JVM.
+ * Note: certain tests throughout this hierarchy require the presence of
+ * the {@code jmxremote_optional.jar} in your classpath. For this reason, these tests are
+ * run only if {@link TestGroup#JMXMP} is enabled. If you wish to run these tests, follow
+ * the instructions in the TestGroup class to enable JMXMP tests. If you run into the
+ * "Unsupported protocol: jmxmp" error, you will need to download the
+ *
+ * JMX Remote API 1.0.1_04 Reference Implementation from Oracle and extract
+ * {@code jmxremote_optional.jar} into your classpath, for example in the {@code lib/ext}
+ * folder of your JVM.
* See also EBR-349.
*
* @author Rob Harrop
* @author Juergen Hoeller
* @author Sam Brannen
+ * @author Chris Beams
*/
-public abstract class AbstractMBeanServerTests extends TestCase {
+public abstract class AbstractMBeanServerTests {
protected MBeanServer server;
- @Override
+ @Before
public final void setUp() throws Exception {
this.server = MBeanServerFactory.createMBeanServer();
try {
@@ -64,8 +70,8 @@ protected ConfigurableApplicationContext loadContext(String configLocation) {
return ctx;
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
releaseServer();
onTearDown();
}
diff --git a/spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java b/spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java
index 7842ee328cb2..e1bd521a1df6 100644
--- a/spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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
@@ -29,18 +29,23 @@
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
-import org.junit.Ignore;
+import org.junit.Test;
import org.springframework.jmx.AbstractMBeanServerTests;
import org.springframework.jmx.IJmxTestBean;
import org.springframework.jmx.JmxException;
import org.springframework.jmx.JmxTestBean;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.export.assembler.AbstractReflectiveMBeanInfoAssembler;
+import org.springframework.tests.Assume;
+import org.springframework.tests.TestGroup;
+
+import static org.junit.Assert.*;
/**
* @author Rob Harrop
* @author Juergen Hoeller
* @author Sam Brannen
+ * @author Chris Beams
*/
public class MBeanClientInterceptorTests extends AbstractMBeanServerTests {
@@ -78,6 +83,7 @@ protected IJmxTestBean getProxy() throws Exception {
return (IJmxTestBean) factory.getObject();
}
+ @Test
public void testProxyClassIsDifferent() throws Exception {
if (!runTests)
return;
@@ -85,6 +91,7 @@ public void testProxyClassIsDifferent() throws Exception {
assertTrue("The proxy class should be different than the base class", (proxy.getClass() != IJmxTestBean.class));
}
+ @Test
public void testDifferentProxiesSameClass() throws Exception {
if (!runTests)
return;
@@ -95,6 +102,7 @@ public void testDifferentProxiesSameClass() throws Exception {
assertSame("The proxy classes should be the same", proxy1.getClass(), proxy2.getClass());
}
+ @Test
public void testGetAttributeValue() throws Exception {
if (!runTests)
return;
@@ -103,6 +111,7 @@ public void testGetAttributeValue() throws Exception {
assertEquals("The age should be 100", 100, age);
}
+ @Test
public void testSetAttributeValue() throws Exception {
if (!runTests)
return;
@@ -111,6 +120,7 @@ public void testSetAttributeValue() throws Exception {
assertEquals("The name of the bean should have been updated", "Rob Harrop", target.getName());
}
+ @Test
public void testSetAttributeValueWithRuntimeException() throws Exception {
if (!runTests)
return;
@@ -123,6 +133,7 @@ public void testSetAttributeValueWithRuntimeException() throws Exception {
}
}
+ @Test
public void testSetAttributeValueWithCheckedException() throws Exception {
if (!runTests)
return;
@@ -135,6 +146,7 @@ public void testSetAttributeValueWithCheckedException() throws Exception {
}
}
+ @Test
public void testSetAttributeValueWithIOException() throws Exception {
if (!runTests)
return;
@@ -147,6 +159,7 @@ public void testSetAttributeValueWithIOException() throws Exception {
}
}
+ @Test
public void testSetReadOnlyAttribute() throws Exception {
if (!runTests)
return;
@@ -159,6 +172,7 @@ public void testSetReadOnlyAttribute() throws Exception {
}
}
+ @Test
public void testInvokeNoArgs() throws Exception {
if (!runTests)
return;
@@ -167,6 +181,7 @@ public void testInvokeNoArgs() throws Exception {
assertEquals("The operation should return 1", 1, result);
}
+ @Test
public void testInvokeArgs() throws Exception {
if (!runTests)
return;
@@ -175,6 +190,7 @@ public void testInvokeArgs() throws Exception {
assertEquals("The operation should return 3", 3, result);
}
+ @Test
public void testInvokeUnexposedMethodWithException() throws Exception {
if (!runTests)
return;
@@ -187,19 +203,13 @@ public void testInvokeUnexposedMethodWithException() throws Exception {
}
}
- // TODO [SPR-8089] Clean up ignored JMX tests.
- //
- // @Ignore should have no effect for JUnit 3.8 tests; however, it appears
- // that tests on the CI server -- as well as those in Eclipse -- do in
- // fact get ignored. So we leave @Ignore here so that developers can
- // easily search for ignored tests.
- //
- // Once fixed, renamed to test* instead of ignore*.
- @Ignore("Requires jmxremote_optional.jar; see comments in AbstractMBeanServerTests for details.")
- public void ignoreTestLazyConnectionToRemote() throws Exception {
+ @Test
+ public void testTestLazyConnectionToRemote() throws Exception {
if (!runTests)
return;
+ Assume.group(TestGroup.JMXMP);
+
JMXServiceURL url = new JMXServiceURL("service:jmx:jmxmp://localhost:9876");
JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(url, null, getServer());
diff --git a/spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTestsIgnore.java b/spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java
similarity index 75%
rename from spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTestsIgnore.java
rename to spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java
index 7082efec132e..74a29b0be018 100644
--- a/spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTestsIgnore.java
+++ b/spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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
@@ -26,19 +26,14 @@
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
-import org.junit.Ignore;
+import org.springframework.tests.Assume;
+import org.springframework.tests.TestGroup;
/**
* @author Rob Harrop
+ * @author Chris Beams
*/
-// TODO [SPR-8089] Clean up ignored JMX tests.
-//
-// @Ignore should have no effect for JUnit 3.8 tests; however, it appears
-// that tests on the CI server -- as well as those in Eclipse -- do in
-// fact get ignored. So we leave @Ignore here so that developers can
-// easily search for ignored tests.
-@Ignore("Requires jmxremote_optional.jar; see comments in AbstractMBeanServerTests for details.")
-public class RemoteMBeanClientInterceptorTestsIgnore extends MBeanClientInterceptorTests {
+public class RemoteMBeanClientInterceptorTests extends MBeanClientInterceptorTests {
private static final String SERVICE_URL = "service:jmx:jmxmp://localhost:9876";
@@ -48,6 +43,9 @@ public class RemoteMBeanClientInterceptorTestsIgnore extends MBeanClientIntercep
@Override
public void onSetUp() throws Exception {
+ runTests = false;
+ Assume.group(TestGroup.JMXMP);
+ runTests = true;
super.onSetUp();
this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(getServiceUrl(), null, getServer());
try {
@@ -73,8 +71,12 @@ public void tearDown() throws Exception {
if (this.connector != null) {
this.connector.close();
}
- this.connectorServer.stop();
- super.tearDown();
+ if (this.connectorServer != null) {
+ this.connectorServer.stop();
+ }
+ if (runTests) {
+ super.tearDown();
+ }
}
}
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/CustomEditorConfigurerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/CustomEditorConfigurerTests.java
index 2c71236d78a7..190190111422 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/CustomEditorConfigurerTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/CustomEditorConfigurerTests.java
@@ -22,8 +22,11 @@
import javax.management.ObjectName;
+import org.junit.Test;
import org.springframework.jmx.AbstractJmxTests;
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
*/
@@ -36,6 +39,7 @@ protected String getApplicationContextPath() {
return "org/springframework/jmx/export/customConfigurer.xml";
}
+ @Test
public void testDatesInJmx() throws Exception {
// System.out.println(getServer().getClass().getName());
ObjectName oname = new ObjectName("bean:name=dateRange");
@@ -47,6 +51,7 @@ public void testDatesInJmx() throws Exception {
assertEquals("endDate ", getEndDate(), endJmx);
}
+ @Test
public void testGetDates() throws Exception {
DateRange dr = (DateRange) getContext().getBean("dateRange");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterOperationsTests.java b/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterOperationsTests.java
index 59740fa0db44..f2bee326688c 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterOperationsTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterOperationsTests.java
@@ -28,6 +28,8 @@
import org.springframework.jmx.export.naming.ObjectNamingStrategy;
import org.springframework.jmx.support.ObjectNameManager;
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
* @author Juergen Hoeller
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java b/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java
index 2d7d9e26398d..c08a9f73b2f7 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java
@@ -33,6 +33,7 @@
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBeanInfo;
+import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@@ -50,6 +51,8 @@
import org.springframework.tests.aop.interceptor.NopInterceptor;
import org.springframework.tests.sample.beans.TestBean;
+import static org.junit.Assert.*;
+
/**
* Integration tests for the {@link MBeanExporter} class.
*
@@ -66,6 +69,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
private static final String OBJECT_NAME = "spring:test=jmxMBeanAdaptor";
@SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
public void testRegisterNonNotificationListenerType() throws Exception {
Map listeners = new HashMap();
// put a non-NotificationListener instance in as a value...
@@ -80,6 +84,7 @@ public void testRegisterNonNotificationListenerType() throws Exception {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
public void testRegisterNullNotificationListenerType() throws Exception {
Map listeners = new HashMap();
// put null in as a value...
@@ -94,6 +99,7 @@ public void testRegisterNullNotificationListenerType() throws Exception {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
public void testRegisterNotificationListenerForNonExistentMBean() throws Exception {
Map listeners = new HashMap();
NotificationListener dummyListener = new NotificationListener() {
@@ -117,6 +123,7 @@ public void handleNotification(Notification notification, Object handback) {
}
}
+ @Test
public void testWithSuppliedMBeanServer() throws Exception {
MBeanExporter exporter = new MBeanExporter();
exporter.setBeans(getBeanMap());
@@ -127,6 +134,7 @@ public void testWithSuppliedMBeanServer() throws Exception {
}
/** Fails if JVM platform MBean server has been started already
+ @Test
public void testWithLocatedMBeanServer() throws Exception {
MBeanExporter adaptor = new MBeanExporter();
adaptor.setBeans(getBeanMap());
@@ -136,6 +144,7 @@ public void testWithLocatedMBeanServer() throws Exception {
}
*/
+ @Test
public void testUserCreatedMBeanRegWithDynamicMBean() throws Exception {
Map map = new HashMap();
map.put("spring:name=dynBean", new TestDynamicMBean());
@@ -153,6 +162,7 @@ public void testUserCreatedMBeanRegWithDynamicMBean() throws Exception {
assertFalse("Assembler should not have been invoked", asm.invoked);
}
+ @Test
public void testAutodetectMBeans() throws Exception {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("autodetectMBeans.xml", getClass()));
@@ -170,6 +180,7 @@ public void testAutodetectMBeans() throws Exception {
}
}
+ @Test
public void testAutodetectWithExclude() throws Exception {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("autodetectMBeans.xml", getClass()));
@@ -189,6 +200,7 @@ public void testAutodetectWithExclude() throws Exception {
}
}
+ @Test
public void testAutodetectLazyMBeans() throws Exception {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("autodetectLazyMBeans.xml", getClass()));
@@ -210,6 +222,7 @@ public void testAutodetectLazyMBeans() throws Exception {
}
}
+ @Test
public void testAutodetectNoMBeans() throws Exception {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("autodetectNoMBeans.xml", getClass()));
@@ -220,6 +233,7 @@ public void testAutodetectNoMBeans() throws Exception {
}
}
+ @Test
public void testWithMBeanExporterListeners() throws Exception {
MockMBeanExporterListener listener1 = new MockMBeanExporterListener();
MockMBeanExporterListener listener2 = new MockMBeanExporterListener();
@@ -235,6 +249,7 @@ public void testWithMBeanExporterListeners() throws Exception {
assertListener(listener2);
}
+ @Test
public void testExportJdkProxy() throws Exception {
JmxTestBean bean = new JmxTestBean();
bean.setName("Rob Harrop");
@@ -260,6 +275,7 @@ public void testExportJdkProxy() throws Exception {
assertEquals("Rob Harrop", nameValue);
}
+ @Test
public void testSelfNaming() throws Exception {
ObjectName objectName = ObjectNameManager.getInstance(OBJECT_NAME);
SelfNamingTestBean testBean = new SelfNamingTestBean();
@@ -278,6 +294,7 @@ public void testSelfNaming() throws Exception {
assertNotNull(instance);
}
+ @Test
public void testRegisterIgnoreExisting() throws Exception {
ObjectName objectName = ObjectNameManager.getInstance(OBJECT_NAME);
@@ -311,6 +328,7 @@ public void testRegisterIgnoreExisting() throws Exception {
assertEquals("Rob Harrop", server.getAttribute(objectName, "Name"));
}
+ @Test
public void testRegisterReplaceExisting() throws Exception {
ObjectName objectName = ObjectNameManager.getInstance(OBJECT_NAME);
@@ -339,6 +357,7 @@ public void testRegisterReplaceExisting() throws Exception {
assertEquals("Sally Greenwood", server.getAttribute(objectName, "Name"));
}
+ @Test
public void testWithExposeClassLoader() throws Exception {
String name = "Rob Harrop";
String otherName = "Juergen Hoeller";
@@ -368,6 +387,7 @@ public void testWithExposeClassLoader() throws Exception {
assertEquals("Incorrect updated name.", otherName, bean.getName());
}
+ @Test
public void testBonaFideMBeanIsNotExportedWhenAutodetectIsTotallyTurnedOff() throws Exception {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
@@ -386,6 +406,7 @@ public void testBonaFideMBeanIsNotExportedWhenAutodetectIsTotallyTurnedOff() thr
exporter.afterPropertiesSet();
}
+ @Test
public void testOnlyBonaFideMBeanIsExportedWhenAutodetectIsMBeanOnly() throws Exception {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
@@ -405,6 +426,7 @@ public void testOnlyBonaFideMBeanIsExportedWhenAutodetectIsMBeanOnly() throws Ex
ObjectNameManager.getInstance(exportedBeanName));
}
+ @Test
public void testBonaFideMBeanAndRegularBeanExporterWithAutodetectAll() throws Exception {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
@@ -428,6 +450,7 @@ public void testBonaFideMBeanAndRegularBeanExporterWithAutodetectAll() throws Ex
ObjectNameManager.getInstance(notToBeExportedBeanName));
}
+ @Test
public void testBonaFideMBeanIsNotExportedWithAutodetectAssembler() throws Exception {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
@@ -450,6 +473,7 @@ public void testBonaFideMBeanIsNotExportedWithAutodetectAssembler() throws Excep
/**
* Want to ensure that said MBean is not exported twice.
*/
+ @Test
public void testBonaFideMBeanExplicitlyExportedAndAutodetectionIsOn() throws Exception {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
@@ -468,6 +492,7 @@ public void testBonaFideMBeanExplicitlyExportedAndAutodetectionIsOn() throws Exc
ObjectNameManager.getInstance(OBJECT_NAME));
}
+ @Test
public void testSetAutodetectModeToOutOfRangeNegativeValue() throws Exception {
try {
MBeanExporter exporter = new MBeanExporter();
@@ -478,6 +503,7 @@ public void testSetAutodetectModeToOutOfRangeNegativeValue() throws Exception {
}
}
+ @Test
public void testSetAutodetectModeToOutOfRangePositiveValue() throws Exception {
try {
MBeanExporter exporter = new MBeanExporter();
@@ -488,6 +514,7 @@ public void testSetAutodetectModeToOutOfRangePositiveValue() throws Exception {
}
}
+ @Test
public void testSetAutodetectModeNameToNull() throws Exception {
try {
MBeanExporter exporter = new MBeanExporter();
@@ -498,6 +525,7 @@ public void testSetAutodetectModeNameToNull() throws Exception {
}
}
+ @Test
public void testSetAutodetectModeNameToAnEmptyString() throws Exception {
try {
MBeanExporter exporter = new MBeanExporter();
@@ -508,6 +536,7 @@ public void testSetAutodetectModeNameToAnEmptyString() throws Exception {
}
}
+ @Test
public void testSetAutodetectModeNameToAWhitespacedString() throws Exception {
try {
MBeanExporter exporter = new MBeanExporter();
@@ -518,6 +547,7 @@ public void testSetAutodetectModeNameToAWhitespacedString() throws Exception {
}
}
+ @Test
public void testSetAutodetectModeNameToARubbishValue() throws Exception {
try {
MBeanExporter exporter = new MBeanExporter();
@@ -528,6 +558,7 @@ public void testSetAutodetectModeNameToARubbishValue() throws Exception {
}
}
+ @Test
public void testNotRunningInBeanFactoryAndPassedBeanNameToExport() throws Exception {
try {
MBeanExporter exporter = new MBeanExporter();
@@ -541,6 +572,7 @@ public void testNotRunningInBeanFactoryAndPassedBeanNameToExport() throws Except
}
}
+ @Test
public void testNotRunningInBeanFactoryAndAutodetectionIsOn() throws Exception {
try {
MBeanExporter exporter = new MBeanExporter();
@@ -555,6 +587,7 @@ public void testNotRunningInBeanFactoryAndAutodetectionIsOn() throws Exception {
/**
* SPR-2158
*/
+ @Test
public void testMBeanIsNotUnregisteredSpuriouslyIfSomeExternalProcessHasUnregisteredMBean() throws Exception {
MBeanExporter exporter = new MBeanExporter();
exporter.setBeans(getBeanMap());
@@ -574,6 +607,7 @@ public void testMBeanIsNotUnregisteredSpuriouslyIfSomeExternalProcessHasUnregist
/**
* SPR-3302
*/
+ @Test
public void testBeanNameCanBeUsedInNotificationListenersMap() throws Exception {
String beanName = "charlesDexterWard";
BeanDefinitionBuilder testBean = BeanDefinitionBuilder.rootBeanDefinition(JmxTestBean.class);
@@ -595,6 +629,7 @@ public void testBeanNameCanBeUsedInNotificationListenersMap() throws Exception {
exporter.afterPropertiesSet();
}
+ @Test
public void testWildcardCanBeUsedInNotificationListenersMap() throws Exception {
String beanName = "charlesDexterWard";
BeanDefinitionBuilder testBean = BeanDefinitionBuilder.rootBeanDefinition(JmxTestBean.class);
@@ -619,6 +654,7 @@ public void testWildcardCanBeUsedInNotificationListenersMap() throws Exception {
/*
* SPR-3625
*/
+ @Test
public void testMBeanIsUnregisteredForRuntimeExceptionDuringInitialization() throws Exception {
BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
BeanDefinitionBuilder builder2 = BeanDefinitionBuilder
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java
index 45244123079c..a6423dcee8db 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java
@@ -26,6 +26,7 @@
import javax.management.NotificationListener;
import javax.management.ObjectName;
+import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.jmx.AbstractMBeanServerTests;
import org.springframework.jmx.JmxTestBean;
@@ -33,6 +34,8 @@
import org.springframework.jmx.export.naming.SelfNaming;
import org.springframework.jmx.support.ObjectNameManager;
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
* @author Mark Fisher
@@ -41,6 +44,7 @@
public class NotificationListenerTests extends AbstractMBeanServerTests {
@SuppressWarnings({"rawtypes", "unchecked"})
+ @Test
public void testRegisterNotificationListenerForMBean() throws Exception {
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
JmxTestBean bean = new JmxTestBean();
@@ -66,6 +70,7 @@ public void testRegisterNotificationListenerForMBean() throws Exception {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
public void testRegisterNotificationListenerWithWildcard() throws Exception {
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
JmxTestBean bean = new JmxTestBean();
@@ -90,6 +95,7 @@ public void testRegisterNotificationListenerWithWildcard() throws Exception {
assertEquals("Listener not notified", 1, listener.getCount(attributeName));
}
+ @Test
public void testRegisterNotificationListenerWithHandback() throws Exception {
String objectName = "spring:name=Test";
JmxTestBean bean = new JmxTestBean();
@@ -120,6 +126,7 @@ public void testRegisterNotificationListenerWithHandback() throws Exception {
assertEquals("Handback object not transmitted correctly", handback, listener.getLastHandback(attributeName));
}
+ @Test
public void testRegisterNotificationListenerForAllMBeans() throws Exception {
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
JmxTestBean bean = new JmxTestBean();
@@ -146,6 +153,7 @@ public void testRegisterNotificationListenerForAllMBeans() throws Exception {
}
@SuppressWarnings("serial")
+ @Test
public void testRegisterNotificationListenerWithFilter() throws Exception {
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
JmxTestBean bean = new JmxTestBean();
@@ -186,6 +194,7 @@ public boolean isNotificationEnabled(Notification notification) {
assertEquals("Listener incorrectly notified for Age", 0, listener.getCount(ageAttribute));
}
+ @Test
public void testCreationWithNoNotificationListenerSet() {
try {
new NotificationListenerBean().afterPropertiesSet();
@@ -195,6 +204,7 @@ public void testCreationWithNoNotificationListenerSet() {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
public void testRegisterNotificationListenerWithBeanNameAndBeanNameInBeansMap() throws Exception {
String beanName = "testBean";
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
@@ -225,6 +235,7 @@ public void testRegisterNotificationListenerWithBeanNameAndBeanNameInBeansMap()
}
@SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
public void testRegisterNotificationListenerWithBeanNameAndBeanInstanceInBeansMap() throws Exception {
String beanName = "testBean";
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
@@ -255,6 +266,7 @@ public void testRegisterNotificationListenerWithBeanNameAndBeanInstanceInBeansMa
}
@SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
public void testRegisterNotificationListenerWithBeanNameBeforeObjectNameMappedToSameBeanInstance() throws Exception {
String beanName = "testBean";
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
@@ -286,6 +298,7 @@ public void testRegisterNotificationListenerWithBeanNameBeforeObjectNameMappedTo
}
@SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
public void testRegisterNotificationListenerWithObjectNameBeforeBeanNameMappedToSameBeanInstance() throws Exception {
String beanName = "testBean";
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
@@ -317,6 +330,7 @@ public void testRegisterNotificationListenerWithObjectNameBeforeBeanNameMappedTo
}
@SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
public void testRegisterNotificationListenerWithTwoBeanNamesMappedToDifferentBeanInstances() throws Exception {
String beanName1 = "testBean1";
String beanName2 = "testBean2";
@@ -359,6 +373,7 @@ public void testRegisterNotificationListenerWithTwoBeanNamesMappedToDifferentBea
assertEquals("Listener not notified for testBean2", 2, listener.getCount("Age"));
}
+ @Test
public void testNotificationListenerRegistrar() throws Exception {
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
JmxTestBean bean = new JmxTestBean();
@@ -391,6 +406,7 @@ public void testNotificationListenerRegistrar() throws Exception {
assertEquals("Listener notified after destruction", 1, listener.getCount(attributeName));
}
+ @Test
public void testNotificationListenerRegistrarWithMultipleNames() throws Exception {
ObjectName objectName = ObjectName.getInstance("spring:name=Test");
ObjectName objectName2 = ObjectName.getInstance("spring:name=Test2");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/NotificationPublisherTests.java b/spring-context/src/test/java/org/springframework/jmx/export/NotificationPublisherTests.java
index a6abda7ed2ef..2237fcc15533 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/NotificationPublisherTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/NotificationPublisherTests.java
@@ -32,12 +32,15 @@
import javax.management.NotificationListener;
import javax.management.ReflectionException;
+import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.jmx.AbstractMBeanServerTests;
import org.springframework.jmx.export.notification.NotificationPublisher;
import org.springframework.jmx.export.notification.NotificationPublisherAware;
import org.springframework.jmx.support.ObjectNameManager;
+import static org.junit.Assert.*;
+
/**
* Integration tests for the Spring JMX {@link NotificationPublisher} functionality.
*
@@ -48,6 +51,7 @@ public class NotificationPublisherTests extends AbstractMBeanServerTests {
private CountingNotificationListener listener = new CountingNotificationListener();
+ @Test
public void testSimpleBean() throws Exception {
// start the MBeanExporter
ConfigurableApplicationContext ctx = loadContext("org/springframework/jmx/export/notificationPublisherTests.xml");
@@ -60,6 +64,7 @@ public void testSimpleBean() throws Exception {
assertEquals("Notification not sent", 1, listener.count);
}
+ @Test
public void testSimpleBeanRegisteredManually() throws Exception {
// start the MBeanExporter
ConfigurableApplicationContext ctx = loadContext("org/springframework/jmx/export/notificationPublisherTests.xml");
@@ -74,6 +79,7 @@ public void testSimpleBeanRegisteredManually() throws Exception {
assertEquals("Notification not sent", 1, listener.count);
}
+ @Test
public void testMBean() throws Exception {
// start the MBeanExporter
ConfigurableApplicationContext ctx = loadContext("org/springframework/jmx/export/notificationPublisherTests.xml");
@@ -86,6 +92,7 @@ public void testMBean() throws Exception {
}
/*
+ @Test
public void testStandardMBean() throws Exception {
// start the MBeanExporter
ApplicationContext ctx = new ClassPathXmlApplicationContext("org/springframework/jmx/export/notificationPublisherTests.xml");
@@ -97,6 +104,7 @@ public void testStandardMBean() throws Exception {
}
*/
+ @Test
public void testLazyInit() throws Exception {
// start the MBeanExporter
ConfigurableApplicationContext ctx = loadContext("org/springframework/jmx/export/notificationPublisherLazyTests.xml");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/PropertyPlaceholderConfigurerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/PropertyPlaceholderConfigurerTests.java
index c95000c59da2..256372eb1bfd 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/PropertyPlaceholderConfigurerTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/PropertyPlaceholderConfigurerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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
@@ -18,11 +18,15 @@
import javax.management.ObjectName;
+import org.junit.Test;
import org.springframework.jmx.AbstractJmxTests;
import org.springframework.jmx.IJmxTestBean;
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
+ * @author Chris Beams
*/
public class PropertyPlaceholderConfigurerTests extends AbstractJmxTests {
@@ -31,6 +35,7 @@ protected String getApplicationContextPath() {
return "org/springframework/jmx/export/propertyPlaceholderConfigurer.xml";
}
+ @Test
public void testPropertiesReplaced() {
IJmxTestBean bean = (IJmxTestBean) getContext().getBean("testBean");
@@ -38,6 +43,7 @@ public void testPropertiesReplaced() {
assertEquals("Age is incorrect", 100, bean.getAge());
}
+ @Test
public void testPropertiesCorrectInJmx() throws Exception {
ObjectName oname = new ObjectName("bean:name=proxyTestBean1");
Object name = getServer().getAttribute(oname, "Name");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationMetadataAssemblerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationMetadataAssemblerTests.java
index d74787b7f81f..11c68dcb99fb 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationMetadataAssemblerTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationMetadataAssemblerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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
@@ -20,15 +20,22 @@
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanOperationInfo;
+import org.junit.Test;
import org.springframework.jmx.IJmxTestBean;
import org.springframework.jmx.export.assembler.AbstractMetadataAssemblerTests;
import org.springframework.jmx.export.metadata.JmxAttributeSource;
-/** @author Rob Harrop */
+import static org.junit.Assert.*;
+
+/**
+ * @author Rob Harrop
+ * @author Chris Beams
+ */
public class AnnotationMetadataAssemblerTests extends AbstractMetadataAssemblerTests {
private static final String OBJECT_NAME = "bean:name=testBean4";
+ @Test
public void testAttributeFromInterface() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = inf.getAttribute("Colour");
@@ -36,12 +43,14 @@ public void testAttributeFromInterface() throws Exception {
assertTrue("The name attribute should be readable", attr.isReadable());
}
+ @Test
public void testOperationFromInterface() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanOperationInfo op = inf.getOperation("fromInterface");
assertNotNull(op);
}
+ @Test
public void testOperationOnGetter() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanOperationInfo op = inf.getOperation("getExpensiveToCalculate");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractJmxAssemblerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractJmxAssemblerTests.java
index 2c4a06e0bee4..42962c5f6426 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractJmxAssemblerTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractJmxAssemblerTests.java
@@ -28,12 +28,16 @@
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanOperationInfo;
+import org.junit.Test;
import org.springframework.jmx.AbstractJmxTests;
import org.springframework.jmx.IJmxTestBean;
import org.springframework.jmx.support.ObjectNameManager;
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
+ * @author Chris Beams
*/
public abstract class AbstractJmxAssemblerTests extends AbstractJmxTests {
@@ -43,12 +47,14 @@ public abstract class AbstractJmxAssemblerTests extends AbstractJmxTests {
protected abstract String getObjectName();
+ @Test
public void testMBeanRegistration() throws Exception {
// beans are registered at this point - just grab them from the server
ObjectInstance instance = getObjectInstance();
assertNotNull("Bean should not be null", instance);
}
+ @Test
public void testRegisterOperations() throws Exception {
IJmxTestBean bean = getBean();
assertNotNull(bean);
@@ -57,6 +63,7 @@ public void testRegisterOperations() throws Exception {
getExpectedOperationCount(), inf.getOperations().length);
}
+ @Test
public void testRegisterAttributes() throws Exception {
IJmxTestBean bean = getBean();
assertNotNull(bean);
@@ -65,11 +72,13 @@ public void testRegisterAttributes() throws Exception {
getExpectedAttributeCount(), inf.getAttributes().length);
}
+ @Test
public void testGetMBeanInfo() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
assertNotNull("MBeanInfo should not be null", info);
}
+ @Test
public void testGetMBeanAttributeInfo() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
MBeanAttributeInfo[] inf = info.getAttributes();
@@ -84,6 +93,7 @@ public void testGetMBeanAttributeInfo() throws Exception {
}
}
+ @Test
public void testGetMBeanOperationInfo() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
MBeanOperationInfo[] inf = info.getOperations();
@@ -98,6 +108,7 @@ public void testGetMBeanOperationInfo() throws Exception {
}
}
+ @Test
public void testDescriptionNotNull() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
@@ -105,6 +116,7 @@ public void testDescriptionNotNull() throws Exception {
info.getDescription());
}
+ @Test
public void testSetAttribute() throws Exception {
ObjectName objectName = ObjectNameManager.getInstance(getObjectName());
getServer().setAttribute(objectName, new Attribute(NAME_ATTRIBUTE, "Rob Harrop"));
@@ -112,6 +124,7 @@ public void testSetAttribute() throws Exception {
assertEquals("Rob Harrop", bean.getName());
}
+ @Test
public void testGetAttribute() throws Exception {
ObjectName objectName = ObjectNameManager.getInstance(getObjectName());
getBean().setName("John Smith");
@@ -119,6 +132,7 @@ public void testGetAttribute() throws Exception {
assertEquals("Incorrect result", "John Smith", val);
}
+ @Test
public void testOperationInvocation() throws Exception{
ObjectName objectName = ObjectNameManager.getInstance(getObjectName());
Object result = getServer().invoke(objectName, "add",
@@ -126,6 +140,7 @@ public void testOperationInvocation() throws Exception{
assertEquals("Incorrect result", new Integer(50), result);
}
+ @Test
public void testAttributeInfoHasDescriptors() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
@@ -141,6 +156,7 @@ public void testAttributeInfoHasDescriptors() throws Exception {
desc.getFieldValue("setMethod"));
}
+ @Test
public void testAttributeHasCorrespondingOperations() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
@@ -159,6 +175,7 @@ public void testAttributeHasCorrespondingOperations() throws Exception {
assertEquals("set operation should have role \"setter\"", "setter", set.getDescriptor().getFieldValue("role"));
}
+ @Test
public void testNotificationMetadata() throws Exception {
ModelMBeanInfo info = (ModelMBeanInfo) getMBeanInfo();
MBeanNotificationInfo[] notifications = info.getNotifications();
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java
index 99cefe715835..0c3ece78395f 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java
@@ -26,6 +26,7 @@
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanOperationInfo;
+import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.jmx.IJmxTestBean;
import org.springframework.jmx.JmxTestBean;
@@ -34,6 +35,8 @@
import org.springframework.jmx.support.ObjectNameManager;
import org.springframework.tests.aop.interceptor.NopInterceptor;
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
* @author Chris Beams
@@ -44,12 +47,14 @@ public abstract class AbstractMetadataAssemblerTests extends AbstractJmxAssemble
protected static final String CACHE_ENTRIES_METRIC = "CacheEntries";
+ @Test
public void testDescription() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
assertEquals("The descriptions are not the same", "My Managed Bean",
info.getDescription());
}
+ @Test
public void testAttributeDescriptionOnSetter() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = inf.getAttribute(AGE_ATTRIBUTE);
@@ -57,6 +62,7 @@ public void testAttributeDescriptionOnSetter() throws Exception {
"The Age Attribute", attr.getDescription());
}
+ @Test
public void testAttributeDescriptionOnGetter() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = inf.getAttribute(NAME_ATTRIBUTE);
@@ -67,12 +73,14 @@ public void testAttributeDescriptionOnGetter() throws Exception {
/**
* Tests the situation where the attribute is only defined on the getter.
*/
+ @Test
public void testReadOnlyAttribute() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = inf.getAttribute(AGE_ATTRIBUTE);
assertFalse("The age attribute should not be writable", attr.isWritable());
}
+ @Test
public void testReadWriteAttribute() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = inf.getAttribute(NAME_ATTRIBUTE);
@@ -83,6 +91,7 @@ public void testReadWriteAttribute() throws Exception {
/**
* Tests the situation where the property only has a getter.
*/
+ @Test
public void testWithOnlySetter() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = inf.getAttribute("NickName");
@@ -92,12 +101,14 @@ public void testWithOnlySetter() throws Exception {
/**
* Tests the situation where the property only has a setter.
*/
+ @Test
public void testWithOnlyGetter() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = info.getAttribute("Superman");
assertNotNull("Attribute should not be null", attr);
}
+ @Test
public void testManagedResourceDescriptor() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
Descriptor desc = info.getMBeanDescriptor();
@@ -111,6 +122,7 @@ public void testManagedResourceDescriptor() throws Exception {
assertEquals("Persist Name should be bar", "bar.jmx", desc.getFieldValue("persistName"));
}
+ @Test
public void testAttributeDescriptor() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
Descriptor desc = info.getAttribute(NAME_ATTRIBUTE).getDescriptor();
@@ -121,6 +133,7 @@ public void testAttributeDescriptor() throws Exception {
assertEquals("Persist Period should be 300", "300", desc.getFieldValue("persistPeriod"));
}
+ @Test
public void testOperationDescriptor() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
Descriptor desc = info.getOperation("myOperation").getDescriptor();
@@ -129,6 +142,7 @@ public void testOperationDescriptor() throws Exception {
assertEquals("Role should be \"operation\"", "operation", desc.getFieldValue("role"));
}
+ @Test
public void testOperationParameterMetadata() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanOperationInfo oper = info.getOperation("add");
@@ -142,6 +156,7 @@ public void testOperationParameterMetadata() throws Exception {
assertEquals("Incorrect type for y param", int.class.getName(), params[1].getType());
}
+ @Test
public void testWithCglibProxy() throws Exception {
IJmxTestBean tb = createJmxTestBean();
ProxyFactory pf = new ProxyFactory();
@@ -169,6 +184,7 @@ public void testWithCglibProxy() throws Exception {
assertTrue("Not included in autodetection", assembler.includeBean(proxy.getClass(), "some bean name"));
}
+ @Test
public void testMetricDescription() throws Exception {
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo metric = inf.getAttribute(QUEUE_SIZE_METRIC);
@@ -179,6 +195,7 @@ public void testMetricDescription() throws Exception {
"The QueueSize metric", operation.getDescription());
}
+ @Test
public void testMetricDescriptor() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
Descriptor desc = info.getAttribute(QUEUE_SIZE_METRIC).getDescriptor();
@@ -191,6 +208,7 @@ public void testMetricDescriptor() throws Exception {
assertEquals("Metric Category should be utilization", "utilization",desc.getFieldValue("metricCategory"));
}
+ @Test
public void testMetricDescriptorDefaults() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
Descriptor desc = info.getAttribute(CACHE_ENTRIES_METRIC).getDescriptor();
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerCustomTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerCustomTests.java
index d4034ed4494c..e7bb1d68c9e5 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerCustomTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerCustomTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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
@@ -19,8 +19,13 @@
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
+ * @author Chris Beams
*/
public class InterfaceBasedMBeanInfoAssemblerCustomTests extends AbstractJmxAssemblerTests {
@@ -48,6 +53,7 @@ protected MBeanInfoAssembler getAssembler() {
return assembler;
}
+ @Test
public void testGetAgeIsReadOnly() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE);
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerMappedTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerMappedTests.java
index 5cd8488eb7a7..1a485f377e6e 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerMappedTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssemblerMappedTests.java
@@ -22,13 +22,19 @@
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
+ * @author Chris Beams
*/
public class InterfaceBasedMBeanInfoAssemblerMappedTests extends AbstractJmxAssemblerTests {
protected static final String OBJECT_NAME = "bean:name=testBean4";
+ @Test
public void testGetAgeIsReadOnly() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE);
@@ -37,6 +43,7 @@ public void testGetAgeIsReadOnly() throws Exception {
assertFalse("Age is not writable", attr.isWritable());
}
+ @Test
public void testWithUnknownClass() throws Exception {
try {
getWithMapping("com.foo.bar.Unknown");
@@ -47,6 +54,7 @@ public void testWithUnknownClass() throws Exception {
}
}
+ @Test
public void testWithNonInterface() throws Exception {
try {
getWithMapping("JmxTestBean");
@@ -57,7 +65,8 @@ public void testWithNonInterface() throws Exception {
}
}
- public void ignoreTestWithFallThrough() throws Exception {
+ @Test
+ public void testWithFallThrough() throws Exception {
InterfaceBasedMBeanInfoAssembler assembler =
getWithMapping("foobar", "org.springframework.jmx.export.assembler.ICustomJmxBean");
assembler.setManagedInterfaces(new Class>[] {IAdditionalTestMethods.class});
@@ -68,6 +77,7 @@ public void ignoreTestWithFallThrough() throws Exception {
assertNickName(attr);
}
+ @Test
public void testNickNameIsExposed() throws Exception {
ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo();
MBeanAttributeInfo attr = inf.getAttribute("NickName");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerComboTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerComboTests.java
index 2c2a8618eb12..ea234b09e8ca 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerComboTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerComboTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -22,14 +22,20 @@
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
/**
* @author Juergen Hoeller
* @author Rob Harrop
+ * @author Chris Beams
*/
public class MethodExclusionMBeanInfoAssemblerComboTests extends AbstractJmxAssemblerTests {
protected static final String OBJECT_NAME = "bean:name=testBean4";
+ @Test
public void testGetAgeIsReadOnly() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE);
@@ -37,6 +43,7 @@ public void testGetAgeIsReadOnly() throws Exception {
assertFalse("Age is not writable", attr.isWritable());
}
+ @Test
public void testNickNameIsExposed() throws Exception {
ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo();
MBeanAttributeInfo attr = inf.getAttribute("NickName");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerMappedTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerMappedTests.java
index 35fe1082703b..aa1e2d57c227 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerMappedTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerMappedTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -22,13 +22,19 @@
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
+ * @author Chris Beams
*/
public class MethodExclusionMBeanInfoAssemblerMappedTests extends AbstractJmxAssemblerTests {
protected static final String OBJECT_NAME = "bean:name=testBean4";
+ @Test
public void testGetAgeIsReadOnly() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE);
@@ -36,6 +42,7 @@ public void testGetAgeIsReadOnly() throws Exception {
assertFalse("Age is not writable", attr.isWritable());
}
+ @Test
public void testNickNameIsExposed() throws Exception {
ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo();
MBeanAttributeInfo attr = inf.getAttribute("NickName");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerNotMappedTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerNotMappedTests.java
index f037d87bcb7d..6b12c74d971f 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerNotMappedTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerNotMappedTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -22,14 +22,20 @@
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
/**
* @author Juergen Hoeller
* @author Rob Harrop
+ * @author Chris Beams
*/
public class MethodExclusionMBeanInfoAssemblerNotMappedTests extends AbstractJmxAssemblerTests {
protected static final String OBJECT_NAME = "bean:name=testBean4";
+ @Test
public void testGetAgeIsReadOnly() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE);
@@ -37,6 +43,7 @@ public void testGetAgeIsReadOnly() throws Exception {
assertTrue("Age is not writable", attr.isWritable());
}
+ @Test
public void testNickNameIsExposed() throws Exception {
ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo();
MBeanAttributeInfo attr = inf.getAttribute("NickName");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerTests.java
index 8a4929300664..53335e50d70f 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssemblerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -22,11 +22,15 @@
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
+import org.junit.Test;
import org.springframework.jmx.JmxTestBean;
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
* @author Rick Evans
+ * @author Chris Beams
*/
public class MethodExclusionMBeanInfoAssemblerTests extends AbstractJmxAssemblerTests {
@@ -60,6 +64,7 @@ protected MBeanInfoAssembler getAssembler() {
return assembler;
}
+ @Test
public void testSupermanIsReadOnly() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = info.getAttribute("Superman");
@@ -71,6 +76,7 @@ public void testSupermanIsReadOnly() throws Exception {
/*
* http://opensource.atlassian.com/projects/spring/browse/SPR-2754
*/
+ @Test
public void testIsNotIgnoredDoesntIgnoreUnspecifiedBeanMethods() throws Exception {
final String beanKey = "myTestBean";
MethodExclusionMBeanInfoAssembler assembler = new MethodExclusionMBeanInfoAssembler();
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java
index 062a45febd79..10b1985515b3 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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
@@ -16,18 +16,25 @@
package org.springframework.jmx.export.assembler;
+import java.util.Properties;
+
import javax.management.MBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
-import java.util.Properties;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
/**
* @author Rob Harrop
+ * @author Chris Beams
*/
public class MethodNameBasedMBeanInfoAssemblerMappedTests extends AbstractJmxAssemblerTests {
protected static final String OBJECT_NAME = "bean:name=testBean4";
+ @Test
public void testGetAgeIsReadOnly() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE);
@@ -36,6 +43,7 @@ public void testGetAgeIsReadOnly() throws Exception {
assertFalse("Age is not writable", attr.isWritable());
}
+ @Test
public void testWithFallThrough() throws Exception {
MethodNameBasedMBeanInfoAssembler assembler =
getWithMapping("foobar", "add,myOperation,getName,setName,getAge");
@@ -47,6 +55,7 @@ public void testWithFallThrough() throws Exception {
assertNickName(attr);
}
+ @Test
public void testNickNameIsExposed() throws Exception {
ModelMBeanInfo inf = (ModelMBeanInfo) getMBeanInfo();
MBeanAttributeInfo attr = inf.getAttribute("NickName");
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java
index 72da54f6f360..d85f42b508e1 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java
@@ -20,9 +20,14 @@
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
/**
* @author Rob Harrop
* @author David Boden
+ * @author Chris Beams
*/
public class MethodNameBasedMBeanInfoAssemblerTests extends AbstractJmxAssemblerTests {
@@ -50,6 +55,7 @@ protected MBeanInfoAssembler getAssembler() {
return assembler;
}
+ @Test
public void testGetAgeIsReadOnly() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
ModelMBeanAttributeInfo attr = info.getAttribute(AGE_ATTRIBUTE);
@@ -58,6 +64,7 @@ public void testGetAgeIsReadOnly() throws Exception {
assertFalse(attr.isWritable());
}
+ @Test
public void testSetNameParameterIsNamed() throws Exception {
ModelMBeanInfo info = getMBeanInfoFromAssembler();
diff --git a/spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTestsIgnore.java b/spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java
similarity index 86%
rename from spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTestsIgnore.java
rename to spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java
index ef244b085e56..6d66caa79cf9 100644
--- a/spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTestsIgnore.java
+++ b/spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2013 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
@@ -28,23 +28,36 @@
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
-import org.junit.Ignore;
+import org.junit.Test;
import org.springframework.jmx.AbstractMBeanServerTests;
+import org.springframework.tests.Assume;
+import org.springframework.tests.TestGroup;
+
+import static org.junit.Assert.*;
/**
* @author Rob Harrop
+ * @author Chris Beams
*/
-// TODO [SPR-8089] Clean up ignored JMX tests.
-//
-// @Ignore should have no effect for JUnit 3.8 tests; however, it appears
-// that tests on the CI server -- as well as those in Eclipse -- do in
-// fact get ignored. So we leave @Ignore here so that developers can
-// easily search for ignored tests.
-@Ignore("Requires jmxremote_optional.jar; see comments in AbstractMBeanServerTests for details.")
-public class ConnectorServerFactoryBeanTestsIgnore extends AbstractMBeanServerTests {
+public class ConnectorServerFactoryBeanTests extends AbstractMBeanServerTests {
private static final String OBJECT_NAME = "spring:type=connector,name=test";
+ private boolean runTests = false;
+
+ @Override
+ protected void onSetUp() throws Exception {
+ Assume.group(TestGroup.JMXMP);
+ runTests = true;
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ if (runTests) {
+ super.tearDown();
+ }
+ }
+ @Test
public void testStartupWithLocatedServer() throws Exception {
ConnectorServerFactoryBean bean = new ConnectorServerFactoryBean();
bean.afterPropertiesSet();
@@ -56,6 +69,7 @@ public void testStartupWithLocatedServer() throws Exception {
}
}
+ @Test
public void testStartupWithSuppliedServer() throws Exception {
//Added a brief snooze here - seems to fix occasional
//java.net.BindException: Address already in use errors
@@ -72,6 +86,7 @@ public void testStartupWithSuppliedServer() throws Exception {
}
}
+ @Test
public void testRegisterWithMBeanServer() throws Exception {
//Added a brief snooze here - seems to fix occasional
//java.net.BindException: Address already in use errors
@@ -89,6 +104,7 @@ public void testRegisterWithMBeanServer() throws Exception {
}
}
+ @Test
public void testNoRegisterWithMBeanServer() throws Exception {
ConnectorServerFactoryBean bean = new ConnectorServerFactoryBean();
bean.afterPropertiesSet();
diff --git a/spring-context/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java b/spring-context/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java
index 598bc73e8c9b..c9c83cffaeed 100644
--- a/spring-context/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -23,9 +23,13 @@
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
-import org.junit.Ignore;
+import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.jmx.AbstractMBeanServerTests;
+import org.springframework.tests.Assume;
+import org.springframework.tests.TestGroup;
+
+import static org.junit.Assert.*;
/**
* @author Rob Harrop
@@ -43,16 +47,9 @@ private JMXConnectorServer getConnectorServer() throws Exception {
return JMXConnectorServerFactory.newJMXConnectorServer(getServiceUrl(), null, getServer());
}
- // TODO [SPR-8089] Clean up ignored JMX tests.
- //
- // @Ignore should have no effect for JUnit 3.8 tests; however, it appears
- // that tests on the CI server -- as well as those in Eclipse -- do in
- // fact get ignored. So we leave @Ignore here so that developers can
- // easily search for ignored tests.
- //
- // Once fixed, renamed to test* instead of ignore*.
- @Ignore("Requires jmxremote_optional.jar; see comments in AbstractMBeanServerTests for details.")
- public void ignoreTestValidConnection() throws Exception {
+ @Test
+ public void testTestValidConnection() throws Exception {
+ Assume.group(TestGroup.JMXMP);
JMXConnectorServer connectorServer = getConnectorServer();
connectorServer.start();
@@ -75,6 +72,7 @@ public void ignoreTestValidConnection() throws Exception {
}
}
+ @Test
public void testWithNoServiceUrl() throws Exception {
MBeanServerConnectionFactoryBean bean = new MBeanServerConnectionFactoryBean();
try {
@@ -85,16 +83,9 @@ public void testWithNoServiceUrl() throws Exception {
}
}
- // TODO [SPR-8089] Clean up ignored JMX tests.
- //
- // @Ignore should have no effect for JUnit 3.8 tests; however, it appears
- // that tests on the CI server -- as well as those in Eclipse -- do in
- // fact get ignored. So we leave @Ignore here so that developers can
- // easily search for ignored tests.
- //
- // Once fixed, renamed to test* instead of ignore*.
- @Ignore("Requires jmxremote_optional.jar; see comments in AbstractMBeanServerTests for details.")
- public void ignoreTestWithLazyConnection() throws Exception {
+ @Test
+ public void testTestWithLazyConnection() throws Exception {
+ Assume.group(TestGroup.JMXMP);
MBeanServerConnectionFactoryBean bean = new MBeanServerConnectionFactoryBean();
bean.setServiceUrl(SERVICE_URL);
bean.setConnectOnStartup(false);
@@ -116,6 +107,7 @@ public void ignoreTestWithLazyConnection() throws Exception {
}
}
+ @Test
public void testWithLazyConnectionAndNoAccess() throws Exception {
MBeanServerConnectionFactoryBean bean = new MBeanServerConnectionFactoryBean();
bean.setServiceUrl(SERVICE_URL);
diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java
index f679713eb96d..028f60c559d4 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java
@@ -66,6 +66,21 @@ public void asyncMethods() throws Exception {
assertEquals("20", future.get());
}
+ @Test
+ public void asyncMethodsThroughInterface() throws Exception {
+ originalThreadName = Thread.currentThread().getName();
+ GenericApplicationContext context = new GenericApplicationContext();
+ context.registerBeanDefinition("asyncTest", new RootBeanDefinition(SimpleAsyncMethodBean.class));
+ context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
+ context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
+ context.refresh();
+ SimpleInterface asyncTest = context.getBean("asyncTest", SimpleInterface.class);
+ asyncTest.doNothing(5);
+ asyncTest.doSomething(10);
+ Future future = asyncTest.returnSomething(20);
+ assertEquals("20", future.get());
+ }
+
@Test
public void asyncMethodsWithQualifier() throws Exception {
originalThreadName = Thread.currentThread().getName();
@@ -86,6 +101,26 @@ public void asyncMethodsWithQualifier() throws Exception {
assertEquals("30", future2.get());
}
+ @Test
+ public void asyncMethodsWithQualifierThroughInterface() throws Exception {
+ originalThreadName = Thread.currentThread().getName();
+ GenericApplicationContext context = new GenericApplicationContext();
+ context.registerBeanDefinition("asyncTest", new RootBeanDefinition(SimpleAsyncMethodWithQualifierBean.class));
+ context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
+ context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
+ context.registerBeanDefinition("e0", new RootBeanDefinition(ThreadPoolTaskExecutor.class));
+ context.registerBeanDefinition("e1", new RootBeanDefinition(ThreadPoolTaskExecutor.class));
+ context.registerBeanDefinition("e2", new RootBeanDefinition(ThreadPoolTaskExecutor.class));
+ context.refresh();
+ SimpleInterface asyncTest = context.getBean("asyncTest", SimpleInterface.class);
+ asyncTest.doNothing(5);
+ asyncTest.doSomething(10);
+ Future future = asyncTest.returnSomething(20);
+ assertEquals("20", future.get());
+ Future future2 = asyncTest.returnSomething2(30);
+ assertEquals("30", future2.get());
+ }
+
@Test
public void asyncClass() throws Exception {
originalThreadName = Thread.currentThread().getName();
@@ -177,6 +212,18 @@ public void asyncPrototypeClassListener() throws Exception {
}
+ public interface SimpleInterface {
+
+ void doNothing(int i);
+
+ void doSomething(int i);
+
+ Future returnSomething(int i);
+
+ Future returnSomething2(int i);
+ }
+
+
public static class AsyncMethodBean {
public void doNothing(int i) {
@@ -196,6 +243,15 @@ public Future returnSomething(int i) {
}
+ public static class SimpleAsyncMethodBean extends AsyncMethodBean implements SimpleInterface {
+
+ @Override
+ public Future returnSomething2(int i) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+
@Async("e0")
public static class AsyncMethodWithQualifierBean {
@@ -224,6 +280,10 @@ public Future returnSomething2(int i) {
}
+ public static class SimpleAsyncMethodWithQualifierBean extends AsyncMethodWithQualifierBean implements SimpleInterface {
+ }
+
+
@Async("e2")
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAsync {
diff --git a/spring-context/src/test/java/org/springframework/scheduling/support/CronSequenceGeneratorTests.java b/spring-context/src/test/java/org/springframework/scheduling/support/CronSequenceGeneratorTests.java
new file mode 100644
index 000000000000..491706f9e31b
--- /dev/null
+++ b/spring-context/src/test/java/org/springframework/scheduling/support/CronSequenceGeneratorTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2002-2013 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
+ *
+ * http://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.support;
+
+import java.util.Date;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author Juergen Hoeller
+ */
+public class CronSequenceGeneratorTests {
+
+ @Test
+ public void testAt50Seconds() {
+ assertEquals(new Date(2012, 6, 2, 1, 0),
+ new CronSequenceGenerator("*/15 * 1-4 * * *").next(new Date(2012, 6, 1, 9, 53, 50)));
+ }
+
+ @Test
+ public void testAt0Seconds() {
+ assertEquals(new Date(2012, 6, 2, 1, 0),
+ new CronSequenceGenerator("*/15 * 1-4 * * *").next(new Date(2012, 6, 1, 9, 53)));
+ }
+
+ @Test
+ public void testAt0Minutes() {
+ assertEquals(new Date(2012, 6, 2, 1, 0),
+ new CronSequenceGenerator("0 */2 1-4 * * *").next(new Date(2012, 6, 1, 9, 0)));
+ }
+
+}
diff --git a/spring-context/src/test/java/org/springframework/scheduling/support/CronTriggerTests.java b/spring-context/src/test/java/org/springframework/scheduling/support/CronTriggerTests.java
index a99bffa1ed8c..90acc959b3b3 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/support/CronTriggerTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/support/CronTriggerTests.java
@@ -41,7 +41,7 @@
@RunWith(Parameterized.class)
public class CronTriggerTests {
- private Calendar calendar = new GregorianCalendar();
+ private final Calendar calendar = new GregorianCalendar();
private final Date date;
@@ -49,8 +49,8 @@ public class CronTriggerTests {
public CronTriggerTests(Date date, TimeZone timeZone) {
- this.timeZone = timeZone;
this.date = date;
+ this.timeZone = timeZone;
}
@Parameters
@@ -66,6 +66,7 @@ private void roundup(Calendar calendar) {
calendar.set(Calendar.MILLISECOND, 0);
}
+
@Before
public void setUp() {
calendar.setTimeZone(timeZone);
diff --git a/spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java b/spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java
index 3e6cac575980..be4f45213a09 100644
--- a/spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java
+++ b/spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java
@@ -42,6 +42,7 @@
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
+import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
@@ -102,6 +103,20 @@ public void testSimpleValidationWithClassLevel() throws Exception {
assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid);
}
+ @Test
+ public void testSpringValidationFieldType() throws Exception {
+ 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);
+ assertEquals(1, errors.getErrorCount());
+ assertThat("Field/Value type mismatch", errors.getFieldError("address").getRejectedValue(),
+ instanceOf(ValidAddress.class));
+ }
+
@Test
public void testSpringValidation() throws Exception {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
@@ -289,8 +304,13 @@ public void initialize(NameAddressValid constraintAnnotation) {
}
@Override
- public boolean isValid(ValidPerson value, ConstraintValidatorContext constraintValidatorContext) {
- return (value.name == null || !value.address.street.contains(value.name));
+ public boolean isValid(ValidPerson value, ConstraintValidatorContext context) {
+ boolean valid = (value.name == null || !value.address.street.contains(value.name));
+ if (!valid && "Phil".equals(value.name)) {
+ context.buildConstraintViolationWithTemplate(
+ context.getDefaultConstraintMessageTemplate()).addNode("address").addConstraintViolation().disableDefaultConstraintViolation();
+ }
+ return valid;
}
}
diff --git a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java
index 3842a741c74f..7d8045b51ba6 100644
--- a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java
+++ b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java
@@ -369,8 +369,7 @@ static Type getRawType(Type genericType, Map typeVariableMap
* all super types, enclosing types and interfaces.
*/
public static Map getTypeVariableMap(Class clazz) {
- Map ref = typeVariableCache.get(clazz);
- Map typeVariableMap = (ref != null ? ref : null);
+ Map typeVariableMap = typeVariableCache.get(clazz);
if (typeVariableMap == null) {
typeVariableMap = new HashMap();
diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java b/spring-core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java
index 62cf4748eae4..7326b3f045f5 100644
--- a/spring-core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java
+++ b/spring-core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
+import org.springframework.util.Assert;
/**
* Converts from a String to a java.lang.Enum by calling {@link Enum#valueOf(Class, String)}.
@@ -29,7 +30,13 @@
final class StringToEnumConverterFactory implements ConverterFactory {
public Converter getConverter(Class targetType) {
- return new StringToEnum(targetType);
+ Class> enumType = targetType;
+ while(enumType != null && !enumType.isEnum()) {
+ enumType = enumType.getSuperclass();
+ }
+ Assert.notNull(enumType, "The target type " + targetType.getName()
+ + " does not refer to an enum");
+ return new StringToEnum(enumType);
}
private class StringToEnum implements Converter {
diff --git a/spring-core/src/main/java/org/springframework/core/env/SystemEnvironmentPropertySource.java b/spring-core/src/main/java/org/springframework/core/env/SystemEnvironmentPropertySource.java
index 09082aad5c22..0baba6a8c196 100644
--- a/spring-core/src/main/java/org/springframework/core/env/SystemEnvironmentPropertySource.java
+++ b/spring-core/src/main/java/org/springframework/core/env/SystemEnvironmentPropertySource.java
@@ -88,10 +88,6 @@ public boolean containsProperty(String name) {
public Object getProperty(String name) {
Assert.notNull(name, "property name must not be null");
String actualName = resolvePropertyName(name);
- if (actualName == null) {
- // at this point we know the property does not exist
- return null;
- }
if (logger.isDebugEnabled() && !name.equals(actualName)) {
logger.debug(String.format(
"PropertySource [%s] does not contain '%s', but found equivalent '%s'",
diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReader.java b/spring-core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReader.java
index b2bf4405da72..af2d4c62d86b 100644
--- a/spring-core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReader.java
+++ b/spring-core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -21,6 +21,7 @@
import java.io.InputStream;
import org.springframework.asm.ClassReader;
+import org.springframework.core.NestedIOException;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
@@ -47,10 +48,14 @@ final class SimpleMetadataReader implements MetadataReader {
SimpleMetadataReader(Resource resource, ClassLoader classLoader) throws IOException {
InputStream is = new BufferedInputStream(resource.getInputStream());
- ClassReader classReader = null;
+ ClassReader classReader;
try {
classReader = new ClassReader(is);
}
+ catch (IllegalArgumentException ex) {
+ throw new NestedIOException("ASM ClassReader failed to parse class file - " +
+ "probably due to a new Java class file version that isn't supported yet: " + resource, ex);
+ }
finally {
is.close();
}
@@ -64,6 +69,7 @@ final class SimpleMetadataReader implements MetadataReader {
this.resource = resource;
}
+
public Resource getResource() {
return this.resource;
}
diff --git a/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java b/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java
index 0ae86e087925..e7fefa175d9d 100644
--- a/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java
+++ b/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java
@@ -317,7 +317,9 @@ else if (!StringUtils.hasText(pattern1)) {
else if (!StringUtils.hasText(pattern2)) {
return pattern1;
}
- else if (!pattern1.equals(pattern2) && !pattern1.contains("{") && match(pattern1, pattern2)) {
+
+ boolean pattern1ContainsUriVar = pattern1.indexOf('{') != -1;
+ if (!pattern1.equals(pattern2) && !pattern1ContainsUriVar && match(pattern1, pattern2)) {
// /* + /hotel -> /hotel ; "/*.*" + "/*.html" -> /*.html
// However /user + /user -> /usr/user ; /{foo} + /bar -> /{foo}/bar
return pattern2;
@@ -344,7 +346,7 @@ else if (pattern1.endsWith("/**")) {
}
else {
int dotPos1 = pattern1.indexOf('.');
- if (dotPos1 == -1) {
+ if (dotPos1 == -1 || pattern1ContainsUriVar) {
// simply concatenate the two patterns
if (pattern1.endsWith("/") || pattern2.startsWith("/")) {
return pattern1 + pattern2;
diff --git a/spring-core/src/main/java/org/springframework/util/FileCopyUtils.java b/spring-core/src/main/java/org/springframework/util/FileCopyUtils.java
index 5aac30908663..2c14da3b517d 100644
--- a/spring-core/src/main/java/org/springframework/util/FileCopyUtils.java
+++ b/spring-core/src/main/java/org/springframework/util/FileCopyUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -31,19 +31,19 @@
import java.io.Writer;
/**
- * Simple utility methods for file and stream copying.
- * All copy methods use a block size of 4096 bytes,
- * and close all affected streams when done.
+ * Simple utility methods for file and stream copying. All copy methods use a block size
+ * of 4096 bytes, and close all affected streams when done. A variation of the copy
+ * methods from this class that leave streams open can be found in {@link StreamUtils}.
*
- *
Mainly for use within the framework,
- * but also useful for application code.
+ *
Mainly for use within the framework, but also useful for application code.
*
* @author Juergen Hoeller
* @since 06.10.2003
+ * @see StreamUtils
*/
public abstract class FileCopyUtils {
- public static final int BUFFER_SIZE = 4096;
+ public static final int BUFFER_SIZE = StreamUtils.BUFFER_SIZE;
//---------------------------------------------------------------------
@@ -106,15 +106,7 @@ public static int copy(InputStream in, OutputStream out) throws IOException {
Assert.notNull(in, "No InputStream specified");
Assert.notNull(out, "No OutputStream specified");
try {
- int byteCount = 0;
- byte[] buffer = new byte[BUFFER_SIZE];
- int bytesRead = -1;
- while ((bytesRead = in.read(buffer)) != -1) {
- out.write(buffer, 0, bytesRead);
- byteCount += bytesRead;
- }
- out.flush();
- return byteCount;
+ return StreamUtils.copy(in, out);
}
finally {
try {
@@ -208,7 +200,7 @@ public static int copy(Reader in, Writer out) throws IOException {
/**
* Copy the contents of the given String to the given output Writer.
- * Closes the write when done.
+ * Closes the writer when done.
* @param in the String to copy from
* @param out the Writer to copy to
* @throws IOException in case of I/O errors
diff --git a/spring-core/src/main/java/org/springframework/util/StreamUtils.java b/spring-core/src/main/java/org/springframework/util/StreamUtils.java
new file mode 100644
index 000000000000..cc3107d81ff0
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/util/StreamUtils.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2002-2013 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
+ *
+ * http://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.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+
+
+/**
+ * Simple utility methods for dealing with streams. The copy methods of this class are
+ * similar to those defined in {@link FileCopyUtils} except that all affected streams are
+ * left open when done. All copy methods use a block size of 4096 bytes.
+ *
+ *
Mainly for use within the framework, but also useful for application code.
+ *
+ * @author Juergen Hoeller
+ * @author Phillip Webb
+ * @since 3.2.2
+ * @see FileCopyUtils
+ */
+public abstract class StreamUtils {
+
+ public static final int BUFFER_SIZE = 4096;
+
+
+ /**
+ * Copy the contents of the given InputStream into a new byte array.
+ * Leaves the stream open when done.
+ * @param in the stream to copy from
+ * @return the new byte array that has been copied to
+ * @throws IOException in case of I/O errors
+ */
+ public static byte[] copyToByteArray(InputStream in) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE);
+ copy(in, out);
+ return out.toByteArray();
+ }
+
+ /**
+ * Copy the contents of the given InputStream into a String.
+ * Leaves the stream open when done.
+ * @param in the InputStream to copy from
+ * @return the String that has been copied to
+ * @throws IOException in case of I/O errors
+ */
+ public static String copyToString(InputStream in, Charset charset) throws IOException {
+ Assert.notNull(in, "No InputStream specified");
+ StringBuilder out = new StringBuilder();
+ InputStreamReader reader = new InputStreamReader(in, charset);
+ char[] buffer = new char[BUFFER_SIZE];
+ int bytesRead = -1;
+ while ((bytesRead = reader.read(buffer)) != -1) {
+ out.append(buffer, 0, bytesRead);
+ }
+ return out.toString();
+ }
+
+ /**
+ * Copy the contents of the given byte array to the given OutputStream.
+ * Leaves the stream open when done.
+ * @param in the byte array to copy from
+ * @param out the OutputStream to copy to
+ * @throws IOException in case of I/O errors
+ */
+ public static void copy(byte[] in, OutputStream out) throws IOException {
+ Assert.notNull(in, "No input byte array specified");
+ Assert.notNull(out, "No OutputStream specified");
+ out.write(in);
+ }
+
+ /**
+ * Copy the contents of the given String to the given output OutputStream.
+ * Leaves the stream open when done.
+ * @param in the String to copy from
+ * @param charset the Charset
+ * @param out the OutputStream to copy to
+ * @throws IOException in case of I/O errors
+ */
+ public static void copy(String in, Charset charset, OutputStream out) throws IOException {
+ Assert.notNull(in, "No input String specified");
+ Assert.notNull(charset, "No charset specified");
+ Assert.notNull(out, "No OutputStream specified");
+ Writer writer = new OutputStreamWriter(out, charset);
+ writer.write(in);
+ writer.flush();
+ }
+
+ /**
+ * Copy the contents of the given InputStream to the given OutputStream.
+ * Leaves both streams open when done.
+ * @param in the InputStream to copy from
+ * @param out the OutputStream to copy to
+ * @return the number of bytes copied
+ * @throws IOException in case of I/O errors
+ */
+ public static int copy(InputStream in, OutputStream out) throws IOException {
+ Assert.notNull(in, "No InputStream specified");
+ Assert.notNull(out, "No OutputStream specified");
+ int byteCount = 0;
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int bytesRead = -1;
+ while ((bytesRead = in.read(buffer)) != -1) {
+ out.write(buffer, 0, bytesRead);
+ byteCount += bytesRead;
+ }
+ out.flush();
+ return byteCount;
+ }
+
+ /**
+ * Returns a variant of the given {@link InputStream} where calling
+ * {@link InputStream#close() close()} has no effect.
+ * @param in the InputStream to decorate
+ * @return a version of the InputStream that ignores calls to close
+ */
+ public static InputStream nonClosing(InputStream in) {
+ Assert.notNull(in, "No InputStream specified");
+ return new NonClosingInputStream(in);
+ }
+
+ /**
+ * Returns a variant of the given {@link OutputStream} where calling
+ * {@link OutputStream#close() close()} has no effect.
+ * @param out the OutputStream to decorate
+ * @return a version of the OutputStream that ignores calls to close
+ */
+ public static OutputStream nonClosing(OutputStream out) {
+ Assert.notNull(out, "No OutputStream specified");
+ return new NonClosingOutputStream(out);
+ }
+
+
+ private static class NonClosingInputStream extends FilterInputStream {
+
+ public NonClosingInputStream(InputStream in) {
+ super(in);
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+ }
+
+
+ private static class NonClosingOutputStream extends FilterOutputStream {
+
+ public NonClosingOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int let) throws IOException {
+ // It is critical that we override this method for performance
+ out.write(b, off, let);
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/util/xml/StaxResult.java b/spring-core/src/main/java/org/springframework/util/xml/StaxResult.java
index c001902252aa..801769cdfab1 100644
--- a/spring-core/src/main/java/org/springframework/util/xml/StaxResult.java
+++ b/spring-core/src/main/java/org/springframework/util/xml/StaxResult.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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,24 +24,24 @@
import org.xml.sax.ContentHandler;
/**
- * Implementation of the {@code Result} tagging interface for StAX writers. Can be constructed with a
- * {@code XMLEventConsumer} or a {@code XMLStreamWriter}.
+ * Implementation of the {@code Result} tagging interface for StAX writers. Can be constructed with
+ * an {@code XMLEventConsumer} or an {@code XMLStreamWriter}.
*
- *
This class is necessary because there is no implementation of {@code Source} for StaxReaders in JAXP 1.3.
- * There is a {@code StAXResult} in JAXP 1.4 (JDK 1.6), but this class is kept around for back-ward compatibility
- * reasons.
+ *
This class is necessary because there is no implementation of {@code Source} for StaxReaders
+ * in JAXP 1.3. There is a {@code StAXResult} in JAXP 1.4 (JDK 1.6), but this class is kept around
+ * for backwards compatibility reasons.
*
*
Even though {@code StaxResult} extends from {@code SAXResult}, calling the methods of
- * {@code SAXResult} is not supported. In general, the only supported operation on this class is
- * to use the {@code ContentHandler} obtained via {@link #getHandler()} to parse an input source using an
- * {@code XMLReader}. Calling {@link #setHandler(org.xml.sax.ContentHandler)} will result in
- * {@code UnsupportedOperationException}s.
+ * {@code SAXResult} is not supported. In general, the only supported operation
+ * on this class is to use the {@code ContentHandler} obtained via {@link #getHandler()} to parse an
+ * input source using an {@code XMLReader}. Calling {@link #setHandler(org.xml.sax.ContentHandler)}
+ * will result in {@code UnsupportedOperationException}s.
*
* @author Arjen Poutsma
+ * @since 3.0
* @see XMLEventWriter
* @see XMLStreamWriter
* @see javax.xml.transform.Transformer
- * @since 3.0
*/
class StaxResult extends SAXResult {
@@ -49,9 +49,9 @@ class StaxResult extends SAXResult {
private XMLStreamWriter streamWriter;
+
/**
- * Constructs a new instance of the {@code StaxResult} with the specified {@code XMLStreamWriter}.
- *
+ * Construct a new instance of the {@code StaxResult} with the specified {@code XMLStreamWriter}.
* @param streamWriter the {@code XMLStreamWriter} to write to
*/
StaxResult(XMLStreamWriter streamWriter) {
@@ -60,8 +60,7 @@ class StaxResult extends SAXResult {
}
/**
- * Constructs a new instance of the {@code StaxResult} with the specified {@code XMLEventWriter}.
- *
+ * Construct a new instance of the {@code StaxResult} with the specified {@code XMLEventWriter}.
* @param eventWriter the {@code XMLEventWriter} to write to
*/
StaxResult(XMLEventWriter eventWriter) {
@@ -70,9 +69,8 @@ class StaxResult extends SAXResult {
}
/**
- * Constructs a new instance of the {@code StaxResult} with the specified {@code XMLEventWriter} and
- * {@code XMLEventFactory}.
- *
+ * Construct a new instance of the {@code StaxResult} with the specified {@code XMLEventWriter}
+ * and {@code XMLEventFactory}.
* @param eventWriter the {@code XMLEventWriter} to write to
* @param eventFactory the {@code XMLEventFactory} to use for creating events
*/
@@ -81,35 +79,35 @@ class StaxResult extends SAXResult {
this.eventWriter = eventWriter;
}
+
/**
- * Returns the {@code XMLEventWriter} used by this {@code StaxResult}. If this {@code StaxResult} was
- * created with an {@code XMLStreamWriter}, the result will be {@code null}.
- *
+ * Return the {@code XMLEventWriter} used by this {@code StaxResult}. If this {@code StaxResult}
+ * was created with an {@code XMLStreamWriter}, the result will be {@code null}.
* @return the StAX event writer used by this result
* @see #StaxResult(javax.xml.stream.XMLEventWriter)
*/
XMLEventWriter getXMLEventWriter() {
- return eventWriter;
+ return this.eventWriter;
}
/**
- * Returns the {@code XMLStreamWriter} used by this {@code StaxResult}. If this {@code StaxResult} was
- * created with an {@code XMLEventConsumer}, the result will be {@code null}.
- *
+ * Return the {@code XMLStreamWriter} used by this {@code StaxResult}. If this {@code StaxResult}
+ * was created with an {@code XMLEventConsumer}, the result will be {@code null}.
* @return the StAX stream writer used by this result
* @see #StaxResult(javax.xml.stream.XMLStreamWriter)
*/
XMLStreamWriter getXMLStreamWriter() {
- return streamWriter;
+ return this.streamWriter;
}
+
/**
- * Throws a {@code UnsupportedOperationException}.
- *
+ * Throws an {@code UnsupportedOperationException}.
* @throws UnsupportedOperationException always
*/
@Override
public void setHandler(ContentHandler handler) {
throw new UnsupportedOperationException("setHandler is not supported");
}
+
}
diff --git a/spring-core/src/main/java/org/springframework/util/xml/StaxSource.java b/spring-core/src/main/java/org/springframework/util/xml/StaxSource.java
index af005ecc1497..5706a4317ed5 100644
--- a/spring-core/src/main/java/org/springframework/util/xml/StaxSource.java
+++ b/spring-core/src/main/java/org/springframework/util/xml/StaxSource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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,24 +24,24 @@
import org.xml.sax.XMLReader;
/**
- * Implementation of the {@code Source} tagging interface for StAX readers. Can be constructed with a
- * {@code XMLEventReader} or a {@code XMLStreamReader}.
+ * Implementation of the {@code Source} tagging interface for StAX readers. Can be constructed with
+ * an {@code XMLEventReader} or an {@code XMLStreamReader}.
*
- *
This class is necessary because there is no implementation of {@code Source} for StAX Readers in JAXP 1.3.
- * There is a {@code StAXSource} in JAXP 1.4 (JDK 1.6), but this class is kept around for back-ward compatibility
- * reasons.
+ *
This class is necessary because there is no implementation of {@code Source} for StAX Readers
+ * in JAXP 1.3. There is a {@code StAXSource} in JAXP 1.4 (JDK 1.6), but this class is kept around
+ * for backwards compatibility reasons.
*
*
Even though {@code StaxSource} extends from {@code SAXSource}, calling the methods of
- * {@code SAXSource} is not supported. In general, the only supported operation on this class is
- * to use the {@code XMLReader} obtained via {@link #getXMLReader()} to parse the input source obtained via {@link
- * #getInputSource()}. Calling {@link #setXMLReader(XMLReader)} or {@link #setInputSource(InputSource)} will result in
- * {@code UnsupportedOperationException}s.
+ * {@code SAXSource} is not supported. In general, the only supported operation
+ * on this class is to use the {@code XMLReader} obtained via {@link #getXMLReader()} to parse the
+ * input source obtained via {@link #getInputSource()}. Calling {@link #setXMLReader(XMLReader)}
+ * or {@link #setInputSource(InputSource)} will result in {@code UnsupportedOperationException}s.
*
* @author Arjen Poutsma
+ * @since 3.0
* @see XMLEventReader
* @see XMLStreamReader
* @see javax.xml.transform.Transformer
- * @since 3.0
*/
class StaxSource extends SAXSource {
@@ -49,11 +49,11 @@ class StaxSource extends SAXSource {
private XMLStreamReader streamReader;
+
/**
- * Constructs a new instance of the {@code StaxSource} with the specified {@code XMLStreamReader}. The
- * supplied stream reader must be in {@code XMLStreamConstants.START_DOCUMENT} or
+ * Construct a new instance of the {@code StaxSource} with the specified {@code XMLStreamReader}.
+ * The supplied stream reader must be in {@code XMLStreamConstants.START_DOCUMENT} or
* {@code XMLStreamConstants.START_ELEMENT} state.
- *
* @param streamReader the {@code XMLStreamReader} to read from
* @throws IllegalStateException if the reader is not at the start of a document or element
*/
@@ -63,10 +63,9 @@ class StaxSource extends SAXSource {
}
/**
- * Constructs a new instance of the {@code StaxSource} with the specified {@code XMLEventReader}. The
- * supplied event reader must be in {@code XMLStreamConstants.START_DOCUMENT} or
+ * Construct a new instance of the {@code StaxSource} with the specified {@code XMLEventReader}.
+ * The supplied event reader must be in {@code XMLStreamConstants.START_DOCUMENT} or
* {@code XMLStreamConstants.START_ELEMENT} state.
- *
* @param eventReader the {@code XMLEventReader} to read from
* @throws IllegalStateException if the reader is not at the start of a document or element
*/
@@ -75,31 +74,30 @@ class StaxSource extends SAXSource {
this.eventReader = eventReader;
}
+
/**
- * Returns the {@code XMLEventReader} used by this {@code StaxSource}. If this {@code StaxSource} was
- * created with an {@code XMLStreamReader}, the result will be {@code null}.
- *
+ * Return the {@code XMLEventReader} used by this {@code StaxSource}. If this {@code StaxSource}
+ * was created with an {@code XMLStreamReader}, the result will be {@code null}.
* @return the StAX event reader used by this source
* @see StaxSource#StaxSource(javax.xml.stream.XMLEventReader)
*/
XMLEventReader getXMLEventReader() {
- return eventReader;
+ return this.eventReader;
}
/**
- * Returns the {@code XMLStreamReader} used by this {@code StaxSource}. If this {@code StaxSource} was
- * created with an {@code XMLEventReader}, the result will be {@code null}.
- *
+ * Return the {@code XMLStreamReader} used by this {@code StaxSource}. If this {@code StaxSource}
+ * was created with an {@code XMLEventReader}, the result will be {@code null}.
* @return the StAX event reader used by this source
* @see StaxSource#StaxSource(javax.xml.stream.XMLEventReader)
*/
XMLStreamReader getXMLStreamReader() {
- return streamReader;
+ return this.streamReader;
}
+
/**
- * Throws a {@code UnsupportedOperationException}.
- *
+ * Throws an {@code UnsupportedOperationException}.
* @throws UnsupportedOperationException always
*/
@Override
@@ -108,12 +106,12 @@ public void setInputSource(InputSource inputSource) {
}
/**
- * Throws a {@code UnsupportedOperationException}.
- *
+ * Throws an {@code UnsupportedOperationException}.
* @throws UnsupportedOperationException always
*/
@Override
public void setXMLReader(XMLReader reader) {
throw new UnsupportedOperationException("setXMLReader is not supported");
}
+
}
diff --git a/spring-core/src/main/java/org/springframework/util/xml/StaxUtils.java b/spring-core/src/main/java/org/springframework/util/xml/StaxUtils.java
index 576f39ebcf56..efafa259d43c 100644
--- a/spring-core/src/main/java/org/springframework/util/xml/StaxUtils.java
+++ b/spring-core/src/main/java/org/springframework/util/xml/StaxUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -45,14 +45,15 @@
*/
public abstract class StaxUtils {
+ // JAXP 1.4 is only available on JDK 1.6+
private static boolean jaxp14Available =
ClassUtils.isPresent("javax.xml.transform.stax.StAXSource", StaxUtils.class.getClassLoader());
+
// Stax Source
/**
* Create a custom, non-JAXP 1.4 StAX {@link Source} for the given {@link XMLStreamReader}.
- *
* @param streamReader the StAX stream reader
* @return a source wrapping the {@code streamReader}
*/
@@ -62,9 +63,8 @@ public static Source createCustomStaxSource(XMLStreamReader streamReader) {
/**
* Create a StAX {@link Source} for the given {@link XMLStreamReader}.
- *
- *
If JAXP 1.4 is available, this method returns a {@link StAXSource}; otherwise it returns a
- * custom StAX Source.
+ *
If JAXP 1.4 is available, this method returns a {@link StAXSource};
+ * otherwise it returns a custom StAX Source.
* @param streamReader the StAX stream reader
* @return a source wrapping the {@code streamReader}
* @see #createCustomStaxSource(XMLStreamReader)
@@ -80,7 +80,6 @@ public static Source createStaxSource(XMLStreamReader streamReader) {
/**
* Create a custom, non-JAXP 1.4 StAX {@link Source} for the given {@link XMLEventReader}.
- *
* @param eventReader the StAX event reader
* @return a source wrapping the {@code eventReader}
*/
@@ -90,9 +89,8 @@ public static Source createCustomStaxSource(XMLEventReader eventReader) {
/**
* Create a StAX {@link Source} for the given {@link XMLEventReader}.
- *
- *
If JAXP 1.4 is available, this method returns a {@link StAXSource}; otherwise it returns a
- * custom StAX Source.
+ *
If JAXP 1.4 is available, this method returns a {@link StAXSource};
+ * otherwise it returns a custom StAX Source.
* @param eventReader the StAX event reader
* @return a source wrapping the {@code eventReader}
* @throws XMLStreamException in case of StAX errors
@@ -116,11 +114,11 @@ public static boolean isStaxSource(Source source) {
return (source instanceof StaxSource || (jaxp14Available && Jaxp14StaxHandler.isStaxSource(source)));
}
+
// Stax Result
/**
* Create a custom, non-JAXP 1.4 StAX {@link Result} for the given {@link XMLStreamWriter}.
- *
* @param streamWriter the StAX stream writer
* @return a source wrapping the {@code streamWriter}
*/
@@ -130,9 +128,8 @@ public static Result createCustomStaxResult(XMLStreamWriter streamWriter) {
/**
* Create a StAX {@link Result} for the given {@link XMLStreamWriter}.
- *
- *
If JAXP 1.4 is available, this method returns a {@link StAXResult}; otherwise it returns a
- * custom StAX Result.
+ *
If JAXP 1.4 is available, this method returns a {@link StAXResult};
+ * otherwise it returns a custom StAX Result.
* @param streamWriter the StAX stream writer
* @return a result wrapping the {@code streamWriter}
* @see #createCustomStaxResult(XMLStreamWriter)
@@ -148,7 +145,6 @@ public static Result createStaxResult(XMLStreamWriter streamWriter) {
/**
* Create a custom, non-JAXP 1.4 StAX {@link Result} for the given {@link XMLEventWriter}.
- *
* @param eventWriter the StAX event writer
* @return a source wrapping the {@code eventWriter}
*/
@@ -158,7 +154,6 @@ public static Result createCustomStaxResult(XMLEventWriter eventWriter) {
/**
* Create a StAX {@link Result} for the given {@link XMLEventWriter}.
- *
*
If JAXP 1.4 is available, this method returns a {@link StAXResult}; otherwise it returns a
* custom StAX Result.
* @param eventWriter the StAX event writer
@@ -177,8 +172,8 @@ public static Result createStaxResult(XMLEventWriter eventWriter) throws XMLStre
/**
* Indicate whether the given {@link javax.xml.transform.Result} is a StAX Result.
- * @return {@code true} if {@code result} is a custom Stax Result or JAXP
- * 1.4 {@link StAXResult}; {@code false} otherwise.
+ * @return {@code true} if {@code result} is a custom Stax Result or JAXP 1.4
+ * {@link StAXResult}; {@code false} otherwise.
*/
public static boolean isStaxResult(Result result) {
return (result instanceof StaxResult || (jaxp14Available && Jaxp14StaxHandler.isStaxResult(result)));
@@ -327,6 +322,7 @@ public static XMLStreamWriter createEventStreamWriter(XMLEventWriter eventWriter
return new XMLEventStreamWriter(eventWriter, eventFactory);
}
+
/**
* Inner class to avoid a static JAXP 1.4 dependency.
*/
@@ -349,11 +345,11 @@ private static Result createStaxResult(XMLEventWriter eventWriter) {
}
private static boolean isStaxSource(Source source) {
- return source instanceof StAXSource;
+ return (source instanceof StAXSource);
}
private static boolean isStaxResult(Result result) {
- return result instanceof StAXResult;
+ return (result instanceof StAXResult);
}
private static XMLStreamReader getXMLStreamReader(Source source) {
diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionTests.java
index 7b2ff0490a11..ba42cddf9daa 100644
--- a/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionTests.java
+++ b/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionTests.java
@@ -17,6 +17,7 @@
package org.springframework.core.convert.support;
import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.*;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -212,6 +213,11 @@ public void testStringToEnum() throws Exception {
assertEquals(Foo.BAR, conversionService.convert("BAR", Foo.class));
}
+ @Test
+ public void testStringToEnumWithSubclss() throws Exception {
+ assertEquals(SubFoo.BAZ, conversionService.convert("BAZ", SubFoo.BAR.getClass()));
+ }
+
@Test
public void testStringToEnumEmptyString() {
assertEquals(null, conversionService.convert("", Foo.class));
@@ -226,6 +232,24 @@ public static enum Foo {
BAR, BAZ;
}
+ public static enum SubFoo {
+
+ BAR {
+ @Override
+ String s() {
+ return "x";
+ }
+ },
+ BAZ {
+ @Override
+ String s() {
+ return "y";
+ }
+ };
+
+ abstract String s();
+ }
+
@Test
public void testStringToLocale() {
assertEquals(Locale.ENGLISH, conversionService.convert("en", Locale.class));
diff --git a/spring-core/src/test/java/org/springframework/tests/TestGroup.java b/spring-core/src/test/java/org/springframework/tests/TestGroup.java
index dcc376eea494..662f0dab532f 100644
--- a/spring-core/src/test/java/org/springframework/tests/TestGroup.java
+++ b/spring-core/src/test/java/org/springframework/tests/TestGroup.java
@@ -21,6 +21,10 @@
import java.util.HashSet;
import java.util.Set;
+import org.springframework.util.StringUtils;
+
+import static java.lang.String.*;
+
/**
* A test group used to limit when certain tests are run.
*
@@ -44,7 +48,13 @@ public enum TestGroup {
* {@code StopWatch}, etc. should be considered a candidate as their successful
* execution is likely to be based on events occurring within a given time window.
*/
- PERFORMANCE;
+ PERFORMANCE,
+
+ /**
+ * Tests requiring the presence of jmxremote_optional.jar in jre/lib/ext in order to
+ * avoid "Unsupported protocol: jmxmp" errors.
+ */
+ JMXMP;
/**
@@ -64,8 +74,10 @@ public static Set parse(String value) {
try {
groups.add(valueOf(group.trim().toUpperCase()));
} catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Unable to find test group '" + group.trim()
- + "' when parsing '" + value + "'");
+ throw new IllegalArgumentException(format(
+ "Unable to find test group '%s' when parsing testGroups value: '%s'. " +
+ "Available groups include: [%s]", group.trim(), value,
+ StringUtils.arrayToCommaDelimitedString(TestGroup.values())));
}
}
return groups;
diff --git a/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java b/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java
index 2b4860fd7284..7f9fe924c4b4 100644
--- a/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java
+++ b/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java
@@ -62,7 +62,9 @@ public void parseInMixedCase() throws Exception {
@Test
public void parseMissing() throws Exception {
thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("Unable to find test group 'missing' when parsing 'performance, missing'");
+ thrown.expectMessage("Unable to find test group 'missing' when parsing " +
+ "testGroups value: 'performance, missing'. Available groups include: " +
+ "[LONG_RUNNING,PERFORMANCE,JMXMP]");
TestGroup.parse("performance, missing");
}
diff --git a/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
index 0a34e1c470ce..05a98f405d4c 100644
--- a/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
+++ b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
@@ -412,6 +412,7 @@ public void combine() {
assertEquals("/*.html", pathMatcher.combine("/*.*", "/*.html"));
assertEquals("/{foo}/bar", pathMatcher.combine("/{foo}", "/bar")); // SPR-8858
assertEquals("/user/user", pathMatcher.combine("/user", "/user")); // SPR-7970
+ assertEquals("/{foo:.*[^0-9].*}/edit/", pathMatcher.combine("/{foo:.*[^0-9].*}", "/edit/")); // SPR-10062
}
@Test
diff --git a/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java b/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java
new file mode 100644
index 000000000000..fe10d2359673
--- /dev/null
+++ b/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2002-2013 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
+ *
+ * http://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.util;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.Random;
+import java.util.UUID;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+
+/**
+ * Tests for {@link StreamUtils}.
+ *
+ * @author Phillip Webb
+ */
+public class StreamUtilsTests {
+
+ private byte[] bytes = new byte[StreamUtils.BUFFER_SIZE + 10];
+
+ private String string = "";
+
+ @Before
+ public void setup() {
+ new Random().nextBytes(bytes);
+ while (string.length() < StreamUtils.BUFFER_SIZE + 10) {
+ string += UUID.randomUUID().toString();
+ }
+ }
+
+ @Test
+ public void copyToByteArray() throws Exception {
+ InputStream inputStream = spy(new ByteArrayInputStream(bytes));
+ byte[] actual = StreamUtils.copyToByteArray(inputStream);
+ assertThat(actual, equalTo(bytes));
+ verify(inputStream, never()).close();
+ }
+
+ @Test
+ public void copyToString() throws Exception {
+ Charset charset = Charset.defaultCharset();
+ InputStream inputStream = spy(new ByteArrayInputStream(string.getBytes(charset)));
+ String actual = StreamUtils.copyToString(inputStream, charset);
+ assertThat(actual, equalTo(string));
+ verify(inputStream, never()).close();
+ }
+
+ @Test
+ public void copyBytes() throws Exception {
+ ByteArrayOutputStream out = spy(new ByteArrayOutputStream());
+ StreamUtils.copy(bytes, out);
+ assertThat(out.toByteArray(), equalTo(bytes));
+ verify(out, never()).close();
+ }
+
+ @Test
+ public void copyString() throws Exception {
+ Charset charset = Charset.defaultCharset();
+ ByteArrayOutputStream out = spy(new ByteArrayOutputStream());
+ StreamUtils.copy(string, charset, out);
+ assertThat(out.toByteArray(), equalTo(string.getBytes(charset)));
+ verify(out, never()).close();
+ }
+
+ @Test
+ public void copyStream() throws Exception {
+ ByteArrayOutputStream out = spy(new ByteArrayOutputStream());
+ StreamUtils.copy(new ByteArrayInputStream(bytes), out);
+ assertThat(out.toByteArray(), equalTo(bytes));
+ verify(out, never()).close();
+ }
+
+ @Test
+ public void nonClosingInputStream() throws Exception {
+ InputStream source = mock(InputStream.class);
+ InputStream nonClosing = StreamUtils.nonClosing(source);
+ nonClosing.read();
+ nonClosing.read(bytes);
+ nonClosing.read(bytes, 1, 2);
+ nonClosing.close();
+ InOrder ordered = inOrder(source);
+ ordered.verify(source).read();
+ ordered.verify(source).read(bytes, 0, bytes.length);
+ ordered.verify(source).read(bytes, 1, 2);
+ ordered.verify(source, never()).close();
+ }
+
+ @Test
+ public void nonClosingOutputStream() throws Exception {
+ OutputStream source = mock(OutputStream.class);
+ OutputStream nonClosing = StreamUtils.nonClosing(source);
+ nonClosing.write(1);
+ nonClosing.write(bytes);
+ nonClosing.write(bytes, 1, 2);
+ nonClosing.close();
+ InOrder ordered = inOrder(source);
+ ordered.verify(source).write(1);
+ ordered.verify(source).write(bytes, 0, bytes.length);
+ ordered.verify(source).write(bytes, 1, 2);
+ ordered.verify(source, never()).close();
+ }
+}
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
index d9ae1a2efb13..3f89bed5121c 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
@@ -109,7 +109,8 @@ public enum SpelMessage {
OPERAND_NOT_DECREMENTABLE(Kind.ERROR,1067,"the expression component ''{0}'' does not support decrement"), //
NOT_ASSIGNABLE(Kind.ERROR,1068,"the expression component ''{0}'' is not assignable"), //
MISSING_CHARACTER(Kind.ERROR,1069,"missing expected character ''{0}''"),
- LEFT_OPERAND_PROBLEM(Kind.ERROR,1070, "Problem parsing left operand");
+ LEFT_OPERAND_PROBLEM(Kind.ERROR,1070, "Problem parsing left operand"),
+ MISSING_SELECTION_EXPRESSION(Kind.ERROR, 1071, "A required selection expression has not been specified");
private Kind kind;
private int code;
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Selection.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Selection.java
index 7489c6ba6969..710e97592163 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Selection.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Selection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -29,6 +29,7 @@
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
+import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -54,7 +55,9 @@ public class Selection extends SpelNodeImpl {
private final boolean nullSafe;
public Selection(boolean nullSafe, int variant,int pos,SpelNodeImpl expression) {
- super(pos,expression);
+ super(pos, expression != null ? new SpelNodeImpl[] { expression }
+ : new SpelNodeImpl[] {});
+ Assert.notNull(expression, "Expression must not be null");
this.nullSafe = nullSafe;
this.variant = variant;
}
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java
index c243b5d7f4b4..7915a3c01572 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java
@@ -557,6 +557,9 @@ private boolean maybeEatSelection(boolean nullSafeNavigation) {
}
nextToken();
SpelNodeImpl expr = eatExpression();
+ if(expr == null) {
+ raiseInternalException(toPos(t), SpelMessage.MISSING_SELECTION_EXPRESSION);
+ }
eatToken(TokenKind.RSQUARE);
if (t.kind==TokenKind.SELECT_FIRST) {
constructedNodes.push(new Selection(nullSafeNavigation,Selection.FIRST,toPos(t),expr));
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java
index c086771cbed8..ce6ad5123be5 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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,13 +19,16 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
@@ -37,7 +40,6 @@
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
-import org.springframework.util.CollectionUtils;
/**
* Reflection-based {@link MethodResolver} used by default in
@@ -92,25 +94,16 @@ public MethodExecutor resolve(EvaluationContext context, Object targetObject, St
try {
TypeConverter typeConverter = context.getTypeConverter();
Class> type = (targetObject instanceof Class ? (Class>) targetObject : targetObject.getClass());
- Method[] methods = getMethods(type, targetObject);
+ List methods = new ArrayList(Arrays.asList(getMethods(type, targetObject)));
// If a filter is registered for this type, call it
MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
if (filter != null) {
- List methodsForFiltering = new ArrayList();
- for (Method method: methods) {
- methodsForFiltering.add(method);
- }
- List methodsFiltered = filter.filter(methodsForFiltering);
- if (CollectionUtils.isEmpty(methodsFiltered)) {
- methods = NO_METHODS;
- }
- else {
- methods = methodsFiltered.toArray(new Method[methodsFiltered.size()]);
- }
+ methods = filter.filter(methods);
}
- Arrays.sort(methods, new Comparator() {
+ // Sort methods into a sensible order
+ Collections.sort(methods, new Comparator() {
public int compare(Method m1, Method m2) {
int m1pl = m1.getParameterTypes().length;
int m2pl = m2.getParameterTypes().length;
@@ -118,6 +111,14 @@ public int compare(Method m1, Method m2) {
}
});
+ // Resolve any bridge methods
+ for (int i = 0; i < methods.size(); i++) {
+ methods.set(i, BridgeMethodResolver.findBridgedMethod(methods.get(i)));
+ }
+
+ // Remove duplicate methods (possible due to resolved bridge methods)
+ methods = new ArrayList(new LinkedHashSet(methods));
+
Method closeMatch = null;
int closeMatchDistance = Integer.MAX_VALUE;
int[] argsToConvert = null;
@@ -125,9 +126,6 @@ public int compare(Method m1, Method m2) {
boolean multipleOptions = false;
for (Method method : methods) {
- if (method.isBridge()) {
- continue;
- }
if (method.getName().equals(name)) {
Class>[] paramTypes = method.getParameterTypes();
List paramDescriptors = new ArrayList(paramTypes.length);
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java
index fdf04c7ba868..e6e28eedd3c4 100644
--- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java
@@ -27,6 +27,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -1736,6 +1737,22 @@ public void SPR_10125() throws Exception {
assertThat(fromClass, is("interfaceValue"));
}
+ @Test
+ public void SPR_10210() throws Exception {
+ StandardEvaluationContext context = new StandardEvaluationContext();
+ context.setVariable("bridgeExample", new org.springframework.expression.spel.spr10210.D());
+ Expression parseExpression = parser.parseExpression("#bridgeExample.bridgeMethod()");
+ parseExpression.getValue(context);
+ }
+
+ @Test
+ public void SPR_10328() throws Exception {
+ thrown.expect(SpelParseException.class);
+ thrown.expectMessage("EL1071E:(pos 2): A required selection expression has not been specified");
+ Expression exp = parser.parseExpression("$[]");
+ exp.getValue(Arrays.asList("foo", "bar", "baz"));
+ }
+
public static class BooleanHolder {
private Boolean simpleProperty = true;
@@ -1796,4 +1813,5 @@ public static class StaticFinalImpl1 extends AbstractStaticFinal implements Stat
public static class StaticFinalImpl2 extends AbstractStaticFinal {
}
+
}
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/A.java b/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/A.java
new file mode 100644
index 000000000000..3098b293c743
--- /dev/null
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/A.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2002-2013 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
+ *
+ * http://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.expression.spel.spr10210;
+
+import org.springframework.expression.spel.spr10210.comp.B;
+import org.springframework.expression.spel.spr10210.infra.C;
+
+abstract class A extends B {
+
+ public void bridgeMethod() {
+ }
+
+}
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/D.java b/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/D.java
new file mode 100644
index 000000000000..e4776d70e66e
--- /dev/null
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/D.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2002-2013 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
+ *
+ * http://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.expression.spel.spr10210;
+
+public class D extends A {
+}
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/comp/B.java b/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/comp/B.java
new file mode 100644
index 000000000000..3250836265ce
--- /dev/null
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/comp/B.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2002-2013 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
+ *
+ * http://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.expression.spel.spr10210.comp;
+
+import java.io.Serializable;
+
+import org.springframework.expression.spel.spr10210.infra.C;
+
+public class B implements Serializable {
+}
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/infra/C.java b/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/infra/C.java
new file mode 100644
index 000000000000..2f0a32e53bee
--- /dev/null
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/spr10210/infra/C.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2002-2013 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
+ *
+ * http://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.expression.spel.spr10210.infra;
+
+public interface C {
+}
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcOperations.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcOperations.java
index 8f5a9964cd39..6db102fc64fb 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcOperations.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcOperations.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -133,7 +133,8 @@ public interface JdbcOperations {
* object via a RowMapper.
*
Uses a JDBC Statement, not a PreparedStatement. If you want to
* execute a static query with a PreparedStatement, use the overloaded
- * {@code queryForObject} method with {@code null} as argument array.
+ * {@link #queryForObject(String, RowMapper, Object...)} method with
+ * {@code null} as argument array.
* @param sql SQL query to execute
* @param rowMapper object that will map one object per row
* @return the single mapped object
@@ -148,7 +149,8 @@ public interface JdbcOperations {
* Execute a query for a result object, given static SQL.
*
Uses a JDBC Statement, not a PreparedStatement. If you want to
* execute a static query with a PreparedStatement, use the overloaded
- * {@code queryForObject} method with {@code null} as argument array.
+ * {@link #queryForObject(String, Class, Object...)} method with
+ * {@code null} as argument array.
*
This method is useful for running static SQL with a known outcome.
* The query is expected to be a single row/single column query; the returned
* result will be directly mapped to the corresponding object type.
@@ -166,7 +168,8 @@ public interface JdbcOperations {
* Execute a query for a result Map, given static SQL.
*
Uses a JDBC Statement, not a PreparedStatement. If you want to
* execute a static query with a PreparedStatement, use the overloaded
- * {@code queryForMap} method with {@code null} as argument array.
+ * {@link #queryForMap(String, Object...)} method with {@code null}
+ * as argument array.
*
The query is expected to be a single row query; the result row will be
* mapped to a Map (one entry for each column, using the column name as the key).
* @param sql SQL query to execute
@@ -194,7 +197,9 @@ public interface JdbcOperations {
* exactly one row, or does not return exactly one column in that row
* @throws DataAccessException if there is any problem executing the query
* @see #queryForLong(String, Object[])
+ * @deprecated in favor of {@link #queryForObject(String, Class)}
*/
+ @Deprecated
long queryForLong(String sql) throws DataAccessException;
/**
@@ -211,7 +216,9 @@ public interface JdbcOperations {
* exactly one row, or does not return exactly one column in that row
* @throws DataAccessException if there is any problem executing the query
* @see #queryForInt(String, Object[])
+ * @deprecated in favor of {@link #queryForObject(String, Class)}
*/
+ @Deprecated
int queryForInt(String sql) throws DataAccessException;
/**
@@ -712,7 +719,9 @@ T queryForObject(String sql, Object[] args, int[] argTypes, Class require
* @throws DataAccessException if the query fails
* @see #queryForLong(String)
* @see java.sql.Types
+ * @deprecated in favor of {@link #queryForObject(String, Object[], int[], Class)} )}
*/
+ @Deprecated
long queryForLong(String sql, Object[] args, int[] argTypes) throws DataAccessException;
/**
@@ -730,7 +739,9 @@ T queryForObject(String sql, Object[] args, int[] argTypes, Class require
* exactly one row, or does not return exactly one column in that row
* @throws DataAccessException if the query fails
* @see #queryForLong(String)
+ * @deprecated in favor of {@link #queryForObject(String, Class, Object[])} )}
*/
+ @Deprecated
long queryForLong(String sql, Object... args) throws DataAccessException;
/**
@@ -748,7 +759,9 @@ T queryForObject(String sql, Object[] args, int[] argTypes, Class require
* @throws DataAccessException if the query fails
* @see #queryForInt(String)
* @see java.sql.Types
+ * @deprecated in favor of {@link #queryForObject(String, Object[], int[], Class)} )}
*/
+ @Deprecated
int queryForInt(String sql, Object[] args, int[] argTypes) throws DataAccessException;
/**
@@ -766,7 +779,9 @@ T queryForObject(String sql, Object[] args, int[] argTypes, Class require
* exactly one row, or does not return exactly one column in that row
* @throws DataAccessException if the query fails
* @see #queryForInt(String)
+ * @deprecated in favor of {@link #queryForObject(String, Class, Object[])} )}
*/
+ @Deprecated
int queryForInt(String sql, Object... args) throws DataAccessException;
/**
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java
index 3f0085cebf41..910d20687229 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -477,11 +477,13 @@ public T queryForObject(String sql, Class requiredType) throws DataAccess
return queryForObject(sql, getSingleColumnRowMapper(requiredType));
}
+ @Deprecated
public long queryForLong(String sql) throws DataAccessException {
Number number = queryForObject(sql, Long.class);
return (number != null ? number.longValue() : 0);
}
+ @Deprecated
public int queryForInt(String sql) throws DataAccessException {
Number number = queryForObject(sql, Integer.class);
return (number != null ? number.intValue() : 0);
@@ -757,21 +759,25 @@ public Map queryForMap(String sql, Object... args) throws DataAc
return queryForObject(sql, args, getColumnMapRowMapper());
}
+ @Deprecated
public long queryForLong(String sql, Object[] args, int[] argTypes) throws DataAccessException {
Number number = queryForObject(sql, args, argTypes, Long.class);
return (number != null ? number.longValue() : 0);
}
+ @Deprecated
public long queryForLong(String sql, Object... args) throws DataAccessException {
Number number = queryForObject(sql, args, Long.class);
return (number != null ? number.longValue() : 0);
}
+ @Deprecated
public int queryForInt(String sql, Object[] args, int[] argTypes) throws DataAccessException {
Number number = queryForObject(sql, args, argTypes, Integer.class);
return (number != null ? number.intValue() : 0);
}
+ @Deprecated
public int queryForInt(String sql, Object... args) throws DataAccessException {
Number number = queryForObject(sql, args, Integer.class);
return (number != null ? number.intValue() : 0);
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataProvider.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataProvider.java
index a3da020588fd..29accf8ffa2d 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataProvider.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -56,33 +56,33 @@ void initializeWithProcedureColumnMetaData(
/**
* Provide any modification of the procedure name passed in to match the meta data currently used.
- * This could include alterig the case.
+ * This could include altering the case.
*/
String procedureNameToUse(String procedureName);
/**
* Provide any modification of the catalog name passed in to match the meta data currently used.
- * This could include alterig the case.
+ * This could include altering the case.
*/
String catalogNameToUse(String catalogName);
/**
* Provide any modification of the schema name passed in to match the meta data currently used.
- * This could include alterig the case.
+ * This could include altering the case.
*/
String schemaNameToUse(String schemaName);
/**
* Provide any modification of the catalog name passed in to match the meta data currently used.
- * The reyurned value will be used for meta data lookups. This could include alterig the case used
- * or providing a base catalog if mone provided.
+ * The returned value will be used for meta data lookups. This could include altering the case used
+ * or providing a base catalog if none is provided.
*/
String metaDataCatalogNameToUse(String catalogName) ;
/**
* Provide any modification of the schema name passed in to match the meta data currently used.
- * The reyurned value will be used for meta data lookups. This could include alterig the case used
- * or providing a base schema if mone provided.
+ * The returned value will be used for meta data lookups. This could include altering the case used
+ * or providing a base schema if none is provided.
*/
String metaDataSchemaNameToUse(String schemaName) ;
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataProvider.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataProvider.java
index 0dff1678c4c6..c7365bed5bce 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataProvider.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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,8 +76,8 @@ void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, String
/**
* Provide any modification of the catalog name passed in to match the meta data currently used.
- * The reyurned value will be used for meta data lookups. This could include alterig the case used or
- * providing a base catalog if mone provided.
+ * The returned value will be used for meta data lookups. This could include altering the case used or
+ * providing a base catalog if none is provided.
*
* @param catalogName
* @return catalog name to use
@@ -86,8 +86,8 @@ void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, String
/**
* Provide any modification of the schema name passed in to match the meta data currently used.
- * The reyurned value will be used for meta data lookups. This could include alterig the case used or
- * providing a base schema if mone provided.
+ * The returned value will be used for meta data lookups. This could include altering the case used or
+ * providing a base schema if none is provided.
*
* @param schemaName
* @return schema name to use
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/EmptySqlParameterSource.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/EmptySqlParameterSource.java
new file mode 100644
index 000000000000..a0b525f0dcd8
--- /dev/null
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/EmptySqlParameterSource.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2002-2013 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
+ *
+ * http://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.jdbc.core.namedparam;
+
+/**
+ * A simple empty implementation of the {@link SqlParameterSource} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.2.2
+ */
+public class EmptySqlParameterSource implements SqlParameterSource {
+
+ /**
+ * A shared instance of {@link EmptySqlParameterSource}.
+ */
+ public static final EmptySqlParameterSource INSTANCE = new EmptySqlParameterSource();
+
+
+ public boolean hasValue(String paramName) {
+ return false;
+ }
+
+ public Object getValue(String paramName) throws IllegalArgumentException {
+ throw new IllegalArgumentException("This SqlParameterSource is empty");
+ }
+
+ public int getSqlType(String paramName) {
+ return TYPE_UNKNOWN;
+ }
+
+ public String getTypeName(String paramName) {
+ return null;
+ }
+
+}
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcOperations.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcOperations.java
index a7f5c9f7c9cc..91e20f3fcd9b 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcOperations.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcOperations.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -88,6 +88,21 @@ T execute(String sql, SqlParameterSource paramSource, PreparedStatementCallb
T execute(String sql, Map paramMap, PreparedStatementCallback action)
throws DataAccessException;
+ /**
+ * Execute a JDBC data access operation, implemented as callback action
+ * working on a JDBC PreparedStatement. This allows for implementing arbitrary
+ * data access operations on a single Statement, within Spring's managed
+ * JDBC environment: that is, participating in Spring-managed transactions
+ * and converting JDBC SQLExceptions into Spring's DataAccessException hierarchy.
+ *
The callback action can return a result object, for example a
+ * domain object or a collection of domain objects.
+ * @param sql SQL to execute
+ * @param action callback object that specifies the action
+ * @return a result object returned by the action, or {@code null}
+ * @throws DataAccessException if there is any problem
+ */
+ T execute(String sql, PreparedStatementCallback action) throws DataAccessException;
+
/**
* Query given SQL to create a prepared statement from SQL and a list
* of arguments to bind to the query, reading the ResultSet with a
@@ -115,6 +130,19 @@ T query(String sql, SqlParameterSource paramSource, ResultSetExtractor rs
T query(String sql, Map paramMap, ResultSetExtractor rse)
throws DataAccessException;
+ /**
+ * Query given SQL to create a prepared statement from SQL,
+ * reading the ResultSet with a ResultSetExtractor.
+ *
Note: In contrast to the JdbcOperations method with the same signature,
+ * this query variant always uses a PreparedStatement. It is effectively
+ * equivalent to a query call with an empty parameter Map.
+ * @param sql SQL query to execute
+ * @param rse object that will extract results
+ * @return an arbitrary result object, as returned by the ResultSetExtractor
+ * @throws org.springframework.dao.DataAccessException if the query fails
+ */
+ T query(String sql, ResultSetExtractor rse) throws DataAccessException;
+
/**
* Query given SQL to create a prepared statement from SQL and a list of
* arguments to bind to the query, reading the ResultSet on a per-row basis
@@ -139,6 +167,18 @@ void query(String sql, SqlParameterSource paramSource, RowCallbackHandler rch)
*/
void query(String sql, Map paramMap, RowCallbackHandler rch) throws DataAccessException;
+ /**
+ * Query given SQL to create a prepared statement from SQL,
+ * reading the ResultSet on a per-row basis with a RowCallbackHandler.
+ *
Note: In contrast to the JdbcOperations method with the same signature,
+ * this query variant always uses a PreparedStatement. It is effectively
+ * equivalent to a query call with an empty parameter Map.
+ * @param sql SQL query to execute
+ * @param rch object that will extract results, one row at a time
+ * @throws org.springframework.dao.DataAccessException if the query fails
+ */
+ void query(String sql, RowCallbackHandler rch) throws DataAccessException;
+
/**
* Query given SQL to create a prepared statement from SQL and a list
* of arguments to bind to the query, mapping each row to a Java object
@@ -166,6 +206,19 @@ List query(String sql, SqlParameterSource paramSource, RowMapper rowMa
List query(String sql, Map paramMap, RowMapper rowMapper)
throws DataAccessException;
+ /**
+ * Query given SQL to create a prepared statement from SQL,
+ * mapping each row to a Java object via a RowMapper.
+ *
Note: In contrast to the JdbcOperations method with the same signature,
+ * this query variant always uses a PreparedStatement. It is effectively
+ * equivalent to a query call with an empty parameter Map.
+ * @param sql SQL query to execute
+ * @param rowMapper object that will map one object per row
+ * @return the result List, containing mapped objects
+ * @throws org.springframework.dao.DataAccessException if the query fails
+ */
+ List query(String sql, RowMapper rowMapper) throws DataAccessException;
+
/**
* Query given SQL to create a prepared statement from SQL and a list
* of arguments to bind to the query, mapping a single result row to a
@@ -245,8 +298,7 @@ T queryForObject(String sql, Map paramMap, Class requiredType)
* @param paramSource container of arguments to bind to the query
* @return the result Map (one entry for each column, using the column name as the key)
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
- * if the query does not return exactly one row, or does not return exactly
- * one column in that row
+ * if the query does not return exactly one row
* @throws org.springframework.dao.DataAccessException if the query fails
* @see org.springframework.jdbc.core.JdbcTemplate#queryForMap(String)
* @see org.springframework.jdbc.core.ColumnMapRowMapper
@@ -266,8 +318,7 @@ T queryForObject(String sql, Map paramMap, Class requiredType)
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
* @return the result Map (one entry for each column, using the column name as the key)
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
- * if the query does not return exactly one row, or does not return exactly
- * one column in that row
+ * if the query does not return exactly one row
* @throws org.springframework.dao.DataAccessException if the query fails
* @see org.springframework.jdbc.core.JdbcTemplate#queryForMap(String)
* @see org.springframework.jdbc.core.ColumnMapRowMapper
@@ -287,7 +338,9 @@ T queryForObject(String sql, Map paramMap, Class requiredType)
* one column in that row
* @throws org.springframework.dao.DataAccessException if the query fails
* @see org.springframework.jdbc.core.JdbcTemplate#queryForLong(String)
+ * @deprecated in favor of {@link #queryForObject(String, SqlParameterSource, Class)}
*/
+ @Deprecated
long queryForLong(String sql, SqlParameterSource paramSource) throws DataAccessException;
/**
@@ -304,7 +357,9 @@ T queryForObject(String sql, Map paramMap, Class requiredType)
* one column in that row
* @throws org.springframework.dao.DataAccessException if the query fails
* @see org.springframework.jdbc.core.JdbcTemplate#queryForLong(String)
+ * @deprecated in favor of {@link #queryForObject(String, Map, Class)}
*/
+ @Deprecated
long queryForLong(String sql, Map paramMap) throws DataAccessException;
/**
@@ -319,7 +374,9 @@ T queryForObject(String sql, Map paramMap, Class requiredType)
* exactly one row, or does not return exactly one column in that row
* @throws org.springframework.dao.DataAccessException if the query fails
* @see org.springframework.jdbc.core.JdbcTemplate#queryForInt(String)
+ * @deprecated in favor of {@link #queryForObject(String, SqlParameterSource, Class)}
*/
+ @Deprecated
int queryForInt(String sql, SqlParameterSource paramSource) throws DataAccessException;
/**
@@ -335,7 +392,9 @@ T queryForObject(String sql, Map paramMap, Class requiredType)
* exactly one row, or does not return exactly one column in that row
* @throws org.springframework.dao.DataAccessException if the query fails
* @see org.springframework.jdbc.core.JdbcTemplate#queryForInt(String)
+ * @deprecated in favor of {@link #queryForObject(String, Map, Class)}
*/
+ @Deprecated
int queryForInt(String sql, Map paramMap) throws DataAccessException;
/**
@@ -378,8 +437,8 @@ List queryForList(String sql, Map paramMap, Class elementTy
* list of arguments to bind to the query, expecting a result list.
*
The results will be mapped to a List (one entry for each row) of
* Maps (one entry for each column, using the column name as the key).
- * Thus Each element in the list will be of the form returned by this interface's
- * queryForMap() methods.
+ * Each element in the list will be of the form returned by this interface's
+ * {@code queryForMap} methods.
* @param sql SQL query to execute
* @param paramSource container of arguments to bind to the query
* @return a List that contains a Map per row
@@ -394,7 +453,7 @@ List queryForList(String sql, Map paramMap, Class elementTy
*
The results will be mapped to a List (one entry for each row) of
* Maps (one entry for each column, using the column name as the key).
* Each element in the list will be of the form returned by this interface's
- * queryForMap() methods.
+ * {@code queryForMap} methods.
* @param sql SQL query to execute
* @param paramMap map of parameters to bind to the query
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
@@ -499,7 +558,7 @@ int update(String sql, SqlParameterSource paramSource, KeyHolder generatedKeyHol
* @param batchValues the array of Maps containing the batch of arguments for the query
* @return an array containing the numbers of rows affected by each update in the batch
*/
- public int[] batchUpdate(String sql, Map[] batchValues);
+ int[] batchUpdate(String sql, Map[] batchValues);
/**
* Execute a batch using the supplied SQL statement with the batch of supplied arguments.
@@ -507,6 +566,6 @@ int update(String sql, SqlParameterSource paramSource, KeyHolder generatedKeyHol
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query
* @return an array containing the numbers of rows affected by each update in the batch
*/
- public int[] batchUpdate(String sql, SqlParameterSource[] batchArgs);
+ int[] batchUpdate(String sql, SqlParameterSource[] batchArgs);
}
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java
index 1abfdea3c218..d8258cefc957 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -137,6 +137,10 @@ public T execute(String sql, Map paramMap, PreparedStatementCallb
return execute(sql, new MapSqlParameterSource(paramMap), action);
}
+ public T execute(String sql, PreparedStatementCallback action) throws DataAccessException {
+ return execute(sql, EmptySqlParameterSource.INSTANCE, action);
+ }
+
public T query(String sql, SqlParameterSource paramSource, ResultSetExtractor rse)
throws DataAccessException {
@@ -149,6 +153,10 @@ public T query(String sql, Map paramMap, ResultSetExtractor rs
return query(sql, new MapSqlParameterSource(paramMap), rse);
}
+ public T query(String sql, ResultSetExtractor rse) throws DataAccessException {
+ return query(sql, EmptySqlParameterSource.INSTANCE, rse);
+ }
+
public void query(String sql, SqlParameterSource paramSource, RowCallbackHandler rch)
throws DataAccessException {
@@ -161,6 +169,10 @@ public void query(String sql, Map paramMap, RowCallbackHandler rch)
query(sql, new MapSqlParameterSource(paramMap), rch);
}
+ public void query(String sql, RowCallbackHandler rch) throws DataAccessException {
+ query(sql, EmptySqlParameterSource.INSTANCE, rch);
+ }
+
public List query(String sql, SqlParameterSource paramSource, RowMapper rowMapper)
throws DataAccessException {
@@ -173,6 +185,10 @@ public List query(String sql, Map paramMap, RowMapper rowMa
return query(sql, new MapSqlParameterSource(paramMap), rowMapper);
}
+ public List query(String sql, RowMapper rowMapper) throws DataAccessException {
+ return query(sql, EmptySqlParameterSource.INSTANCE, rowMapper);
+ }
+
public T queryForObject(String sql, SqlParameterSource paramSource, RowMapper rowMapper)
throws DataAccessException {
@@ -206,20 +222,24 @@ public Map queryForMap(String sql, Map paramMap) thro
return queryForObject(sql, paramMap, new ColumnMapRowMapper());
}
+ @Deprecated
public long queryForLong(String sql, SqlParameterSource paramSource) throws DataAccessException {
Number number = queryForObject(sql, paramSource, Long.class);
return (number != null ? number.longValue() : 0);
}
+ @Deprecated
public long queryForLong(String sql, Map paramMap) throws DataAccessException {
return queryForLong(sql, new MapSqlParameterSource(paramMap));
}
+ @Deprecated
public int queryForInt(String sql, SqlParameterSource paramSource) throws DataAccessException {
Number number = queryForObject(sql, paramSource, Integer.class);
return (number != null ? number.intValue() : 0);
}
+ @Deprecated
public int queryForInt(String sql, Map paramMap) throws DataAccessException {
return queryForInt(sql, new MapSqlParameterSource(paramMap));
}
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcCall.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcCall.java
index 7c80a14d0fec..12e1dbd85ef0 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcCall.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcCall.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -97,7 +97,7 @@ protected AbstractJdbcCall(JdbcTemplate jdbcTemplate) {
/**
- * Get the configured {@link JdbcTemplate}
+ * Get the configured {@link JdbcTemplate}.
*/
public JdbcTemplate getJdbcTemplate() {
return this.jdbcTemplate;
@@ -110,7 +110,6 @@ protected CallableStatementCreatorFactory getCallableStatementFactory() {
return this.callableStatementFactory;
}
-
/**
* Set the name of the stored procedure.
*/
@@ -294,7 +293,7 @@ protected void compileInternal() {
this.callMetaDataContext.createReturnResultSetParameter(entry.getKey(), entry.getValue());
this.declaredParameters.add(resultSetParameter);
}
- callMetaDataContext.processParameters(this.declaredParameters);
+ this.callMetaDataContext.processParameters(this.declaredParameters);
this.callString = this.callMetaDataContext.createCallString();
if (logger.isDebugEnabled()) {
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcInsert.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcInsert.java
index 98f0e5991ebb..cb66d803c70f 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcInsert.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcInsert.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -74,9 +74,9 @@ public abstract class AbstractJdbcInsert {
private final List declaredColumns = new ArrayList();
/**
- * Has this operation been compiled? Compilation means at
- * least checking that a DataSource or JdbcTemplate has been provided,
- * but subclasses may also implement their own custom validation.
+ * Has this operation been compiled? Compilation means at least checking
+ * that a DataSource or JdbcTemplate has been provided, but subclasses
+ * may also implement their own custom validation.
*/
private boolean compiled = false;
@@ -108,9 +108,16 @@ protected AbstractJdbcInsert(JdbcTemplate jdbcTemplate) {
//-------------------------------------------------------------------------
- // Methods dealing with configuaration properties
+ // Methods dealing with configuration properties
//-------------------------------------------------------------------------
+ /**
+ * Get the {@link JdbcTemplate} that is configured to be used.
+ */
+ public JdbcTemplate getJdbcTemplate() {
+ return this.jdbcTemplate;
+ }
+
/**
* Set the name of the table for this insert
*/
@@ -230,41 +237,31 @@ public int[] getInsertTypes() {
return this.insertTypes;
}
- /**
- * Get the {@link JdbcTemplate} that is configured to be used
- */
- protected JdbcTemplate getJdbcTemplate() {
- return this.jdbcTemplate;
- }
-
//-------------------------------------------------------------------------
// Methods handling compilation issues
//-------------------------------------------------------------------------
/**
- * Compile this JdbcInsert using provided parameters and meta data plus other settings. This
- * finalizes the configuration for this object and subsequent attempts to compile are ignored.
- * This will be implicitly called the first time an un-compiled insert is executed.
- * @throws org.springframework.dao.InvalidDataAccessApiUsageException if the object hasn't
- * been correctly initialized, for example if no DataSource has been provided
+ * Compile this JdbcInsert using provided parameters and meta data plus other settings.
+ * This finalizes the configuration for this object and subsequent attempts to compile are
+ * ignored. This will be implicitly called the first time an un-compiled insert is executed.
+ * @throws InvalidDataAccessApiUsageException if the object hasn't been correctly initialized,
+ * for example if no DataSource has been provided
*/
public synchronized final void compile() throws InvalidDataAccessApiUsageException {
if (!isCompiled()) {
if (getTableName() == null) {
throw new InvalidDataAccessApiUsageException("Table name is required");
}
-
try {
this.jdbcTemplate.afterPropertiesSet();
}
catch (IllegalArgumentException ex) {
throw new InvalidDataAccessApiUsageException(ex.getMessage());
}
-
compileInternal();
this.compiled = true;
-
if (logger.isDebugEnabled()) {
logger.debug("JdbcInsert for table [" + getTableName() + "] compiled");
}
@@ -272,21 +269,17 @@ public synchronized final void compile() throws InvalidDataAccessApiUsageExcepti
}
/**
- * Method to perform the actual compilation. Subclasses can override this template method to perform
- * their own compilation. Invoked after this base class's compilation is complete.
+ * Method to perform the actual compilation. Subclasses can override this template method
+ * to perform their own compilation. Invoked after this base class's compilation is complete.
*/
protected void compileInternal() {
-
- tableMetaDataContext.processMetaData(getJdbcTemplate().getDataSource(), getColumnNames(), getGeneratedKeyNames());
-
- insertString = tableMetaDataContext.createInsertString(getGeneratedKeyNames());
-
- insertTypes = tableMetaDataContext.createInsertTypes();
-
+ this.tableMetaDataContext.processMetaData(
+ getJdbcTemplate().getDataSource(), getColumnNames(), getGeneratedKeyNames());
+ this.insertString = this.tableMetaDataContext.createInsertString(getGeneratedKeyNames());
+ this.insertTypes = this.tableMetaDataContext.createInsertTypes();
if (logger.isDebugEnabled()) {
- logger.debug("Compiled JdbcInsert. Insert string is [" + getInsertString() + "]");
+ logger.debug("Compiled insert object: insert string is [" + getInsertString() + "]");
}
-
onCompileInternal();
}
@@ -318,12 +311,13 @@ protected void checkCompiled() {
}
/**
- * Method to check whether we are allowd to make any configuration changes at this time. If the class has been
- * compiled, then no further changes to the configuration are allowed.
+ * Method to check whether we are allowd to make any configuration changes at this time.
+ * If the class has been compiled, then no further changes to the configuration are allowed.
*/
protected void checkIfConfigurationModificationIsAllowed() {
if (isCompiled()) {
- throw new InvalidDataAccessApiUsageException("Configuration can't be altered once the class has been compiled or used.");
+ throw new InvalidDataAccessApiUsageException(
+ "Configuration can't be altered once the class has been compiled or used");
}
}
@@ -334,7 +328,6 @@ protected void checkIfConfigurationModificationIsAllowed() {
/**
* Method that provides execution of the insert using the passed in Map of parameters
- *
* @param args Map with parameter names and values to be used in insert
* @return number of rows affected
*/
@@ -346,7 +339,6 @@ protected int doExecute(Map args) {
/**
* Method that provides execution of the insert using the passed in {@link SqlParameterSource}
- *
* @param parameterSource parameter names and values to be used in insert
* @return number of rows affected
*/
@@ -357,14 +349,13 @@ protected int doExecute(SqlParameterSource parameterSource) {
}
/**
- * Method to execute the insert
+ * Method to execute the insert.
*/
private int executeInsertInternal(List