diff --git a/build.gradle b/build.gradle
index b299841b..9cf50a19 100644
--- a/build.gradle
+++ b/build.gradle
@@ -18,12 +18,19 @@ configure(allprojects) {
}
configure(subprojects) { subproject ->
+
apply plugin: "java"
apply plugin: "propdeps"
apply from: "${rootProject.projectDir}/publish-maven.gradle"
- sourceCompatibility=1.5
- targetCompatibility=1.5
+ compileJava {
+ sourceCompatibility=1.5
+ targetCompatibility=1.5
+ }
+ compileTestJava {
+ sourceCompatibility=1.6
+ targetCompatibility=1.6
+ }
[compileJava, compileTestJava]*.options*.compilerArgs = ["-Xlint:none"]
@@ -54,7 +61,7 @@ configure(subprojects.findAll {it.name != "spring-js-resources"}) { subproject -
}
subproject.ext {
- springVersion = "3.2.1.RELEASE"
+ springVersion = "4.0.0.RELEASE"
springSecurityVersion = "3.1.3.RELEASE"
slf4jVersion = "1.6.1"
log4jVersion = "1.2.15"
@@ -124,7 +131,7 @@ project("spring-js") {
dependencies {
compile(project(":spring-js-resources"))
compile("commons-logging:commons-logging:1.1.1")
- provided("javax.servlet:servlet-api:2.4")
+ provided("javax.servlet:javax.servlet-api:3.0.1")
optional("org.apache.tiles:tiles-api:2.1.2")
optional("org.apache.tiles:tiles-core:2.1.2")
optional("org.apache.tiles:tiles-jsp:2.1.2")
@@ -153,13 +160,12 @@ project("spring-webflow") {
compile(project(":spring-js"))
compile("commons-logging:commons-logging:1.1.1")
provided("javax.el:el-api:2.2")
- provided("javax.persistence:persistence-api:1.0.2")
- provided("javax.servlet:servlet-api:2.4")
+ provided("org.eclipse.persistence:javax.persistence:2.0.0")
+ provided("javax.servlet:javax.servlet-api:3.0.1")
provided("javax.portlet:portlet-api:2.0")
- provided("javax.transaction:transaction-api:1.1-rev-1")
provided("junit:junit:3.8.2")
compile("opensymphony:ognl:2.6.11")
- optional("org.hibernate:hibernate:3.2.7.ga") {
+ optional("org.hibernate:hibernate-core:3.6.9.Final") {
exclude group: "org.slf4j", module: "slf4j-api"
}
optional("backport-util-concurrent:backport-util-concurrent:3.0")
@@ -175,10 +181,9 @@ project("spring-webflow") {
optional("org.springframework:spring-webmvc-portlet:$springVersion")
optional("org.springframework.security:spring-security-core:$springSecurityVersion")
testCompile("javax.validation:validation-api:1.0.0.GA")
- testCompile("org.apache.openjpa:openjpa:1.1.0")
- testCompile("org.apache.openjpa:openjpa-lib:1.1.0")
- testCompile("org.apache.openjpa:openjpa-persistence:1.1.0")
- testCompile("org.apache.openjpa:openjpa-persistence-jdbc:1.1.0")
+ testCompile("org.hibernate:hibernate-core:3.6.9.Final")
+ testCompile("org.hibernate:hibernate-entitymanager:3.6.9.Final")
+ testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
testCompile("org.hsqldb:hsqldb:2.2.8")
testCompile("org.jboss.el:jboss-el:2.0.1.GA")
testCompile("org.springframework:spring-aop:$springVersion")
@@ -194,7 +199,7 @@ project("spring-faces") {
compile(project(":spring-binding"))
compile(project(":spring-webflow"))
compile("commons-logging:commons-logging:1.1.1")
- provided("javax.servlet:servlet-api:2.4")
+ provided("javax.servlet:javax.servlet-api:3.0.1")
provided("javax.portlet:portlet-api:2.0")
provided("javax.el:el-api:1.0")
compile("org.springframework:spring-beans:$springVersion")
diff --git a/spring-binding/src/main/java/org/springframework/binding/collection/AbstractCachingMapDecorator.java b/spring-binding/src/main/java/org/springframework/binding/collection/AbstractCachingMapDecorator.java
new file mode 100644
index 00000000..c03f2b22
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/collection/AbstractCachingMapDecorator.java
@@ -0,0 +1,295 @@
+package org.springframework.binding.collection;
+
+import java.io.Serializable;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.springframework.util.Assert;
+
+/**
+ * A simple decorator for a Map, encapsulating the workflow for caching
+ * expensive values in a target Map. Supports caching weak or strong keys.
+ *
+ * This class is an abstract template. Caching Map implementations should
+ * subclass and override the create(key) method which encapsulates
+ * expensive creation of a new object.
+ *
+ * @author Keith Donald
+ * @author Juergen Hoeller
+ * @since 2.4
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractCachingMapDecorator implements Map, Serializable {
+
+ private static Object NULL_VALUE = new Object();
+
+
+ private final Map targetMap;
+
+ private final boolean synchronize;
+
+ private final boolean weak;
+
+
+ /**
+ * Create a CachingMapDecorator with strong keys,
+ * using an underlying synchronized Map.
+ */
+ public AbstractCachingMapDecorator() {
+ this(false);
+ }
+
+ /**
+ * Create a CachingMapDecorator,
+ * using an underlying synchronized Map.
+ * @param weak whether to use weak references for keys and values
+ */
+ public AbstractCachingMapDecorator(boolean weak) {
+ Map internalMap = (weak ? new WeakHashMap() : new HashMap());
+ this.targetMap = Collections.synchronizedMap(internalMap);
+ this.synchronize = true;
+ this.weak = weak;
+ }
+
+ /**
+ * Create a CachingMapDecorator with initial size,
+ * using an underlying synchronized Map.
+ * @param weak whether to use weak references for keys and values
+ * @param size the initial cache size
+ */
+ public AbstractCachingMapDecorator(boolean weak, int size) {
+ Map internalMap = weak ? new WeakHashMap (size) : new HashMap(size);
+ this.targetMap = Collections.synchronizedMap(internalMap);
+ this.synchronize = true;
+ this.weak = weak;
+ }
+
+ /**
+ * Create a CachingMapDecorator for the given Map.
+ * The passed-in Map won't get synchronized explicitly,
+ * so make sure to pass in a properly synchronized Map, if desired.
+ * @param targetMap the Map to decorate
+ */
+ public AbstractCachingMapDecorator(Map targetMap) {
+ this(targetMap, false, false);
+ }
+
+ /**
+ * Create a CachingMapDecorator for the given Map.
+ * The passed-in Map won't get synchronized explicitly unless
+ * you specify "synchronize" as "true".
+ * @param targetMap the Map to decorate
+ * @param synchronize whether to synchronize on the given Map
+ * @param weak whether to use weak references for values
+ */
+ @SuppressWarnings("unchecked")
+ public AbstractCachingMapDecorator(Map targetMap, boolean synchronize, boolean weak) {
+ Assert.notNull(targetMap, "'targetMap' must not be null");
+ this.targetMap = (Map) (synchronize ? Collections.synchronizedMap(targetMap) : targetMap);
+ this.synchronize = synchronize;
+ this.weak = weak;
+ }
+
+
+ public int size() {
+ return this.targetMap.size();
+ }
+
+ public boolean isEmpty() {
+ return this.targetMap.isEmpty();
+ }
+
+ public boolean containsKey(Object key) {
+ return this.targetMap.containsKey(key);
+ }
+
+ public boolean containsValue(Object value) {
+ Object valueToCheck = (value != null ? value : NULL_VALUE);
+ if (this.synchronize) {
+ synchronized (this.targetMap) {
+ return containsValueOrReference(valueToCheck);
+ }
+ }
+ else {
+ return containsValueOrReference(valueToCheck);
+ }
+ }
+
+ private boolean containsValueOrReference(Object value) {
+ if (this.targetMap.containsValue(value)) {
+ return true;
+ }
+ for (Object mapVal : this.targetMap.values()) {
+ if (mapVal instanceof Reference && value.equals(((Reference) mapVal).get())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public V remove(Object key) {
+ return unwrapReturnValue(this.targetMap.remove(key));
+ }
+
+ @SuppressWarnings("unchecked")
+ private V unwrapReturnValue(Object value) {
+ Object returnValue = value;
+ if (returnValue instanceof Reference) {
+ returnValue = ((Reference) returnValue).get();
+ }
+ return (returnValue == NULL_VALUE ? null : (V) returnValue);
+ }
+
+ public void putAll(Map extends K, ? extends V> map) {
+ this.targetMap.putAll(map);
+ }
+
+ public void clear() {
+ this.targetMap.clear();
+ }
+
+ public Set keySet() {
+ if (this.synchronize) {
+ synchronized (this.targetMap) {
+ return new LinkedHashSet(this.targetMap.keySet());
+ }
+ }
+ else {
+ return new LinkedHashSet(this.targetMap.keySet());
+ }
+ }
+
+ public Collection values() {
+ if (this.synchronize) {
+ synchronized (this.targetMap) {
+ return valuesCopy();
+ }
+ }
+ else {
+ return valuesCopy();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Collection valuesCopy() {
+ LinkedList values = new LinkedList();
+ for (Iterator it = this.targetMap.values().iterator(); it.hasNext();) {
+ Object value = it.next();
+ if (value instanceof Reference) {
+ value = ((Reference) value).get();
+ if (value == null) {
+ it.remove();
+ continue;
+ }
+ }
+ values.add(value == NULL_VALUE ? null : (V) value);
+ }
+ return values;
+ }
+
+ public Set> entrySet() {
+ if (this.synchronize) {
+ synchronized (this.targetMap) {
+ return entryCopy();
+ }
+ }
+ else {
+ return entryCopy();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Set> entryCopy() {
+ Map entries = new LinkedHashMap();
+ for (Iterator> it = this.targetMap.entrySet().iterator(); it.hasNext();) {
+ Entry entry = it.next();
+ Object value = entry.getValue();
+ if (value instanceof Reference) {
+ value = ((Reference) value).get();
+ if (value == null) {
+ it.remove();
+ continue;
+ }
+ }
+ entries.put(entry.getKey(), value == NULL_VALUE ? null : (V) value);
+ }
+ return entries.entrySet();
+ }
+
+
+ /**
+ * Put an object into the cache, possibly wrapping it with a weak
+ * reference.
+ * @see #useWeakValue(Object, Object)
+ */
+ public V put(K key, V value) {
+ Object newValue = value;
+ if (value == null) {
+ newValue = NULL_VALUE;
+ }
+ else if (useWeakValue(key, value)) {
+ newValue = new WeakReference(newValue);
+ }
+ return unwrapReturnValue(this.targetMap.put(key, newValue));
+ }
+
+ /**
+ * Decide whether to use a weak reference for the value of
+ * the given key-value pair.
+ * @param key the candidate key
+ * @param value the candidate value
+ * @return true in order to use a weak reference;
+ * false otherwise.
+ */
+ protected boolean useWeakValue(K key, V value) {
+ return this.weak;
+ }
+
+ /**
+ * Get value for key.
+ * Creates and caches value if it doesn't already exist in the cache.
+ * This implementation is not synchronized: This is highly
+ * concurrent but does not guarantee unique instances in the cache,
+ * as multiple values for the same key could get created in parallel.
+ * Consider overriding this method to synchronize it, if desired.
+ * @see #create(Object)
+ */
+ @SuppressWarnings("unchecked")
+ public V get(Object key) {
+ Object value = this.targetMap.get(key);
+ if (value instanceof Reference) {
+ value = ((Reference) value).get();
+ }
+ if (value == null) {
+ V newValue = create((K) key);
+ put((K) key, newValue);
+ return newValue;
+ }
+ return (value == NULL_VALUE ? null : (V) value);
+ }
+
+ /**
+ * Create a value to cache for the given key.
+ * Called by get if there is no value cached already.
+ * @param key the cache key
+ * @see #get(Object)
+ */
+ protected abstract V create(K key);
+
+
+ @Override
+ public String toString() {
+ return "CachingMapDecorator [" + getClass().getName() + "]:" + this.targetMap;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java
index 4a854f86..9655c0fd 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java
@@ -138,12 +138,10 @@ public class ArrayToCollection implements TwoWayConverter {
if (elementConverter != null) {
return elementConverter;
} else {
- if (JdkVersion.isAtLeastJava15()) {
- Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
- if (elementType != null) {
- Class componentType = source.getClass().getComponentType();
- return conversionService.getConversionExecutor(componentType, elementType);
- }
+ Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
+ if (elementType != null) {
+ Class componentType = source.getClass().getComponentType();
+ return conversionService.getConversionExecutor(componentType, elementType);
}
return null;
}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/CollectionToCollection.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/CollectionToCollection.java
index f4b81442..a6698e53 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/CollectionToCollection.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/CollectionToCollection.java
@@ -90,12 +90,10 @@ public class CollectionToCollection implements Converter {
if (elementConverter != null) {
return elementConverter;
} else {
- if (JdkVersion.isAtLeastJava15()) {
- Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
- if (elementType != null) {
- Class componentType = source.getClass().getComponentType();
- return conversionService.getConversionExecutor(componentType, elementType);
- }
+ Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
+ if (elementType != null) {
+ Class componentType = source.getClass().getComponentType();
+ return conversionService.getConversionExecutor(componentType, elementType);
}
return null;
}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToCollection.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToCollection.java
index 6228685a..c8be6534 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToCollection.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToCollection.java
@@ -105,12 +105,10 @@ public class ObjectToCollection implements Converter {
if (elementConverter != null) {
return elementConverter;
} else {
- if (JdkVersion.isAtLeastJava15()) {
- Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
- if (elementType != null) {
- Class componentType = source.getClass().getComponentType();
- return conversionService.getConversionExecutor(componentType, elementType);
- }
+ Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
+ if (elementType != null) {
+ Class componentType = source.getClass().getComponentType();
+ return conversionService.getConversionExecutor(componentType, elementType);
}
return null;
}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToLabeledEnum.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToLabeledEnum.java
deleted file mode 100644
index 3baab27a..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToLabeledEnum.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2004-2008 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.binding.convert.converters;
-
-import org.springframework.core.enums.LabeledEnum;
-import org.springframework.core.enums.LabeledEnumResolver;
-import org.springframework.core.enums.StaticLabeledEnumResolver;
-
-/**
- * Converts from a textual representation to a {@link LabeledEnum}. The text should be the enum's label.
- *
- * @author Keith Donald
- */
-public class StringToLabeledEnum extends StringToObject {
-
- private LabeledEnumResolver labeledEnumResolver = StaticLabeledEnumResolver.instance();
-
- public StringToLabeledEnum() {
- super(LabeledEnum.class);
- }
-
- protected Object toObject(String string, Class targetClass) throws Exception {
- return labeledEnumResolver.getLabeledEnumByLabel(targetClass, string);
- }
-
- protected String toString(Object object) throws Exception {
- LabeledEnum labeledEnum = (LabeledEnum) object;
- return labeledEnum.getLabel();
- }
-
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContext.java b/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContext.java
index 0be57f58..e33df0c9 100644
--- a/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContext.java
+++ b/spring-binding/src/main/java/org/springframework/binding/message/DefaultMessageContext.java
@@ -26,11 +26,11 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.binding.collection.AbstractCachingMapDecorator;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.core.style.ToStringCreator;
-import org.springframework.util.CachingMapDecorator;
/**
* The default message context implementation. Uses a {@link MessageSource} to resolve messages that are added by
@@ -44,9 +44,12 @@ public class DefaultMessageContext implements StateManageableMessageContext {
private MessageSource messageSource;
- private Map sourceMessages = new CachingMapDecorator(new LinkedHashMap()) {
- protected Object create(Object source) {
- return new ArrayList();
+ @SuppressWarnings("serial")
+ private Map> sourceMessages = new AbstractCachingMapDecorator>(
+ new LinkedHashMap>()) {
+
+ protected List create(Object source) {
+ return new ArrayList();
}
};
diff --git a/spring-binding/src/main/java/org/springframework/binding/method/MethodInvoker.java b/spring-binding/src/main/java/org/springframework/binding/method/MethodInvoker.java
index 49f4dd1c..677cb67e 100644
--- a/spring-binding/src/main/java/org/springframework/binding/method/MethodInvoker.java
+++ b/spring-binding/src/main/java/org/springframework/binding/method/MethodInvoker.java
@@ -17,13 +17,14 @@ package org.springframework.binding.method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.binding.collection.AbstractCachingMapDecorator;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.convert.service.DefaultConversionService;
import org.springframework.core.style.StylerUtils;
-import org.springframework.util.CachingMapDecorator;
/**
* A helper for invoking typed methods on arbitrary objects, with support for argument value type conversion from values
@@ -44,9 +45,10 @@ public class MethodInvoker {
/**
* A cache of invoked bean methods, keyed weakly.
*/
- private CachingMapDecorator methodCache = new CachingMapDecorator(true) {
- public Object create(Object key) {
- return ((MethodKey) key).getMethod();
+ @SuppressWarnings("serial")
+ private Map methodCache = new AbstractCachingMapDecorator(true) {
+ public Method create(MethodKey key) {
+ return key.getMethod();
}
};
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/SpringBeanWebFlowVariableResolver.java b/spring-faces/src/main/java/org/springframework/faces/webflow/SpringBeanWebFlowVariableResolver.java
index 3e410b74..ad7adb8c 100644
--- a/spring-faces/src/main/java/org/springframework/faces/webflow/SpringBeanWebFlowVariableResolver.java
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/SpringBeanWebFlowVariableResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2008 the original author or authors.
+ * Copyright 2004-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,25 +16,124 @@
package org.springframework.faces.webflow;
import javax.faces.context.FacesContext;
+import javax.faces.el.EvaluationException;
import javax.faces.el.VariableResolver;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
-import org.springframework.web.jsf.SpringBeanVariableResolver;
+import org.springframework.util.Assert;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.RequestContextHolder;
/**
- * JSF 1.1 variable resolver for Spring Beans accessible to the flow's local bean factory.
+ * JSF 1.1 {@code VariableResolver} that delegates to the
+ * flow's local Spring bean factory (for resolving Spring beans) and then
+ * to the original resolver of the underlying JSF implementation
+ * (for resolving managed-bean objects as defined in {@code faces-config.xml}
+ * as well as well-known implicit EL attributes).
+ *
+ * Configure this resolver in your {@code faces-config.xml} file as follows:
+ *
+ *
+ * <application>
+ * ...
+ * <variable-resolver>org.springframework.faces.webflow.SpringBeanWebFlowVariableResolver</variable-resolver>
+ * </application>
+ *
+ * All your JSF expressions can then implicitly refer to the names of
+ * Spring-managed service layer beans, for example in property values of
+ * JSF-managed beans:
+ *
+ *
+ * <managed-bean>
+ * <managed-bean-name>myJsfManagedBean</managed-bean-name>
+ * <managed-bean-class>example.MyJsfManagedBean</managed-bean-class>
+ * <managed-bean-scope>session</managed-bean-scope>
+ * <managed-property>
+ * <property-name>mySpringManagedBusinessObject</property-name>
+ * <value>#{mySpringManagedBusinessObject}</value>
+ * </managed-property>
+ * </managed-bean>
+ *
+ * with "mySpringManagedBusinessObject" defined as Spring bean in
+ * applicationContext.xml:
+ *
+ *
+ * <bean id="mySpringManagedBusinessObject" class="example.MySpringManagedBusinessObject">
+ * ...
+ * </bean>
*
* @author Jeremy Grelle
*/
-public class SpringBeanWebFlowVariableResolver extends SpringBeanVariableResolver {
+public class SpringBeanWebFlowVariableResolver extends VariableResolver {
private static final BeanFactory EMPTY_BEAN_FACTORY = new StaticListableBeanFactory();
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ protected final VariableResolver originalVariableResolver;
+
+
public SpringBeanWebFlowVariableResolver(VariableResolver originalVariableResolver) {
- super(originalVariableResolver);
+ Assert.notNull(originalVariableResolver, "Original JSF VariableResolver must not be null");
+ this.originalVariableResolver = originalVariableResolver;
+ }
+
+ /**
+ * Return the original JSF VariableResolver that this resolver delegates to.
+ * Used to resolve standard JSF-managed beans.
+ */
+ protected final VariableResolver getOriginalVariableResolver() {
+ return this.originalVariableResolver;
+ }
+
+
+ /**
+ * Try to resolve the variable as Spring bean in the flow local bean factory.
+ * Then delegate to the original VariableResolver.
+ */
+ @Override
+ public Object resolveVariable(FacesContext facesContext, String name) throws EvaluationException {
+ Object bean = resolveSpringBean(facesContext, name);
+ if (bean != null) {
+ return bean;
+ }
+ Object value = resolveOriginal(facesContext, name);
+ if (value != null) {
+ return value;
+ }
+ return null;
+
+ }
+
+ /**
+ * Resolve the attribute via the original JSF VariableResolver.
+ */
+ protected Object resolveOriginal(FacesContext facesContext, String name) {
+ Object value = getOriginalVariableResolver().resolveVariable(facesContext, name);
+ if (value != null && logger.isTraceEnabled()) {
+ logger.trace("Successfully resolved variable '" + name + "' via original VariableResolver");
+ }
+ return value;
+ }
+
+ /**
+ * Resolve the attribute as a Spring bean in the ApplicationContext.
+ */
+ protected Object resolveSpringBean(FacesContext facesContext, String name) {
+ BeanFactory bf = getBeanFactory(facesContext);
+ if (bf.containsBean(name)) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Successfully resolved variable '" + name + "' in Spring BeanFactory");
+ }
+ return bf.getBean(name);
+ }
+ else {
+ return null;
+ }
}
protected BeanFactory getBeanFactory(FacesContext facesContext) {
diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/TreeStructureManager.java b/spring-faces/src/main/java/org/springframework/faces/webflow/TreeStructureManager.java
index 853c508c..b14b5c8e 100644
--- a/spring-faces/src/main/java/org/springframework/faces/webflow/TreeStructureManager.java
+++ b/spring-faces/src/main/java/org/springframework/faces/webflow/TreeStructureManager.java
@@ -94,7 +94,7 @@ class TreeStructureManager {
String compId = treeStructComp.getComponentId();
UIComponent component;
try {
- component = (UIComponent) BeanUtils.instantiateClass(ClassUtils.forName(compClass));
+ component = (UIComponent) BeanUtils.instantiateClass(ClassUtils.forName(compClass, TreeStructureManager.class.getClassLoader()));
} catch (Exception ex) {
throw new FacesException("Could not restore the component tree structure.", ex);
}
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/action/DispatchMethodInvoker.java b/spring-webflow/src/main/java/org/springframework/webflow/action/DispatchMethodInvoker.java
index 9f0278fb..b1e9f969 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/action/DispatchMethodInvoker.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/action/DispatchMethodInvoker.java
@@ -19,10 +19,10 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
+import org.springframework.binding.collection.AbstractCachingMapDecorator;
import org.springframework.binding.method.InvalidMethodKeyException;
import org.springframework.binding.method.MethodKey;
import org.springframework.util.Assert;
-import org.springframework.util.CachingMapDecorator;
/**
* Invoker and cache for dispatch methods that all share the same target object. The dispatch methods typically share
@@ -46,8 +46,9 @@ class DispatchMethodInvoker {
/**
* The resolved method cache.
*/
- private Map methodCache = new CachingMapDecorator() {
- public Object create(Object key) {
+ @SuppressWarnings("serial")
+ private Map methodCache = new AbstractCachingMapDecorator() {
+ public Method create(String key) {
String methodName = (String) key;
try {
return new MethodKey(target.getClass(), methodName, parameterTypes).getMethod();
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/action/ResultObjectBasedEventFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/action/ResultObjectBasedEventFactory.java
index a4df2342..f296f2e0 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/action/ResultObjectBasedEventFactory.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/action/ResultObjectBasedEventFactory.java
@@ -16,7 +16,6 @@
package org.springframework.webflow.action;
import org.springframework.core.JdkVersion;
-import org.springframework.core.enums.LabeledEnum;
import org.springframework.util.StringUtils;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
@@ -75,9 +74,6 @@ public class ResultObjectBasedEventFactory extends EventFactorySupport implement
return event(source, getNullEventId());
} else if (isBoolean(resultObject.getClass())) {
return event(source, ((Boolean) resultObject).booleanValue());
- } else if (isLabeledEnum(resultObject.getClass())) {
- String resultId = ((LabeledEnum) resultObject).getLabel();
- return event(source, resultId, getResultAttributeName(), resultObject);
} else if (isJdk5Enum(resultObject.getClass())) {
String eventId = EnumUtils.getEnumName(resultObject);
return event(source, eventId, getResultAttributeName(), resultObject);
@@ -101,7 +97,7 @@ public class ResultObjectBasedEventFactory extends EventFactorySupport implement
* Check whether or not given type is mapped to a corresponding event using special mapping rules.
*/
public boolean isMappedValueType(Class type) {
- return isBoolean(type) || isLabeledEnum(type) || isJdk5Enum(type) || isString(type) || isEvent(type);
+ return isBoolean(type) || isJdk5Enum(type) || isString(type) || isEvent(type);
}
// internal helpers to determine the 'type' of a class
@@ -110,10 +106,6 @@ public class ResultObjectBasedEventFactory extends EventFactorySupport implement
return Boolean.class.equals(type) || boolean.class.equals(type);
}
- private boolean isLabeledEnum(Class type) {
- return LabeledEnum.class.isAssignableFrom(type);
- }
-
private boolean isJdk5Enum(Class type) {
if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_15) {
return EnumUtils.isEnum(type);
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ConversationContainer.java b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ConversationContainer.java
index 2a52b777..6bf61309 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ConversationContainer.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ConversationContainer.java
@@ -111,11 +111,7 @@ class ConversationContainer implements Serializable {
}
private ConversationId nextId() {
- if (JdkVersion.isAtLeastJava15()) {
- return new SimpleConversationId(Integer.valueOf(++conversationIdSequence));
- } else {
- return new SimpleConversationId(new Integer(++conversationIdSequence));
- }
+ return new SimpleConversationId(Integer.valueOf(++conversationIdSequence));
}
/**
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/SimpleFlowExecutionSnapshotGroup.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/SimpleFlowExecutionSnapshotGroup.java
index 642c7f74..ba6ee553 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/SimpleFlowExecutionSnapshotGroup.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/SimpleFlowExecutionSnapshotGroup.java
@@ -109,12 +109,7 @@ class SimpleFlowExecutionSnapshotGroup implements FlowExecutionSnapshotGroup, Se
}
public Serializable nextSnapshotId() {
- Integer nextSnapshotId;
- if (JdkVersion.isAtLeastJava15()) {
- nextSnapshotId = Integer.valueOf(snapshotIdSequence);
- } else {
- nextSnapshotId = new Integer(snapshotIdSequence);
- }
+ Integer nextSnapshotId = Integer.valueOf(snapshotIdSequence);
snapshotIdSequence++;
return nextSnapshotId;
}
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/FlowResourceFlowViewResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/FlowResourceFlowViewResolver.java
index da0f9923..ca202b59 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/FlowResourceFlowViewResolver.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/FlowResourceFlowViewResolver.java
@@ -35,7 +35,8 @@ import org.springframework.webflow.mvc.view.FlowViewResolver;
*/
public class FlowResourceFlowViewResolver implements FlowViewResolver {
- private static final boolean JSTL_PRESENT = ClassUtils.isPresent("javax.servlet.jsp.jstl.fmt.LocalizationContext");
+ private static final boolean JSTL_PRESENT = ClassUtils.isPresent(
+ "javax.servlet.jsp.jstl.fmt.LocalizationContext", FlowResourceFlowViewResolver.class.getClassLoader());
private String defaultViewSuffix = ".jsp";
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/MvcEnvironment.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/MvcEnvironment.java
index a2de6d0c..9956f586 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/MvcEnvironment.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/MvcEnvironment.java
@@ -43,7 +43,8 @@ public enum MvcEnvironment {
* @return the web environment the context is running in, or null if not running in a web environment
*/
public static MvcEnvironment environmentFor(ApplicationContext applicationContext) {
- if (ClassUtils.isPresent("javax.portlet.PortletContext") && isPortletApplicationContext(applicationContext)) {
+ if (ClassUtils.isPresent("javax.portlet.PortletContext",
+ MvcEnvironment.class.getClassLoader()) && isPortletApplicationContext(applicationContext)) {
return MvcEnvironment.PORTLET;
} else if (applicationContext instanceof WebApplicationContext) {
return MvcEnvironment.SERVLET;
@@ -53,8 +54,8 @@ public enum MvcEnvironment {
}
private static boolean isPortletApplicationContext(ApplicationContext applicationContext) {
- return ClassUtils.isPresent("org.springframework.web.portlet.context.ConfigurablePortletApplicationContext")
- && applicationContext instanceof ConfigurablePortletApplicationContext;
+ return ClassUtils.isPresent("org.springframework.web.portlet.context.ConfigurablePortletApplicationContext",
+ MvcEnvironment.class.getClassLoader()) && applicationContext instanceof ConfigurablePortletApplicationContext;
}
}
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaFlowExecutionListenerTests.java b/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaFlowExecutionListenerTests.java
index 612b1c0b..9bcf4486 100644
--- a/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaFlowExecutionListenerTests.java
+++ b/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaFlowExecutionListenerTests.java
@@ -1,19 +1,21 @@
package org.springframework.webflow.persistence;
+import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import junit.framework.TestCase;
import org.springframework.core.io.ClassPathResource;
+import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
-import org.springframework.orm.jpa.JpaTemplate;
+import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
-import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.webflow.engine.EndState;
import org.springframework.webflow.execution.FlowExecutionException;
@@ -28,8 +30,6 @@ public class JpaFlowExecutionListenerTests extends TestCase {
private JdbcTemplate jdbcTemplate;
- private JpaTemplate jpaTemplate;
-
public void testTemp() {
}
@@ -41,7 +41,6 @@ public class JpaFlowExecutionListenerTests extends TestCase {
entityManagerFactory = getEntityManagerFactory(dataSource);
JpaTransactionManager tm = new JpaTransactionManager(entityManagerFactory);
jpaListener = new JpaFlowExecutionListener(entityManagerFactory, tm);
- jpaTemplate = new JpaTemplate(entityManagerFactory);
}
public void testFlowNotAPersistenceContext() {
@@ -61,7 +60,8 @@ public class JpaFlowExecutionListenerTests extends TestCase {
assertSessionBound();
TestBean bean = new TestBean(1, "Keith Donald");
- jpaTemplate.persist(bean);
+ EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
+ em.persist(bean);
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
EndState endState = new EndState(flowSession.getDefinitionInternal(), "success");
@@ -84,14 +84,17 @@ public class JpaFlowExecutionListenerTests extends TestCase {
assertSessionBound();
TestBean bean1 = new TestBean(1, "Keith Donald");
- jpaTemplate.persist(bean1);
+
+ EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
+ em.persist(bean1);
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
jpaListener.paused(context);
assertSessionNotBound();
jpaListener.resuming(context);
TestBean bean2 = new TestBean(2, "Keith Donald");
- jpaTemplate.persist(bean2);
+ em = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
+ em.persist(bean2);
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertSessionBound();
@@ -116,7 +119,8 @@ public class JpaFlowExecutionListenerTests extends TestCase {
assertSessionBound();
TestBean bean = new TestBean(1, "Keith Donald");
- jpaTemplate.persist(bean);
+ EntityManager emf = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
+ emf.persist(bean);
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
EndState endState = new EndState(flowSession.getDefinitionInternal(), "cancel");
@@ -157,7 +161,8 @@ public class JpaFlowExecutionListenerTests extends TestCase {
assertSessionBound();
TestBean bean = new TestBean(1, "Keith Donald");
- jpaTemplate.persist(bean);
+ EntityManager emf = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
+ emf.persist(bean);
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
jpaListener.exceptionThrown(context, new FlowExecutionException("bla", "bla", "bla"));
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
@@ -197,8 +202,7 @@ public class JpaFlowExecutionListenerTests extends TestCase {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource);
factory.setPersistenceXmlLocation("classpath:org/springframework/webflow/persistence/persistence.xml");
- OpenJpaVendorAdapter openJpa = new OpenJpaVendorAdapter();
- factory.setJpaVendorAdapter(openJpa);
+ factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.afterPropertiesSet();
return factory.getObject();
}
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaFlowManagedPersistenceIntegrationTests.java b/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaFlowManagedPersistenceIntegrationTests.java
index 055c65e4..14e1b6a5 100644
--- a/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaFlowManagedPersistenceIntegrationTests.java
+++ b/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaFlowManagedPersistenceIntegrationTests.java
@@ -6,7 +6,7 @@ import javax.sql.DataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
-import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.Event;
@@ -31,7 +31,7 @@ public class JpaFlowManagedPersistenceIntegrationTests extends AbstractFlowManag
public Event execute(RequestContext context) throws Exception {
assertSessionBound();
EntityManager em = (EntityManager) context.getFlowScope().get("persistenceContext");
- TestBean bean = (TestBean) em.getReference(TestBean.class, new Integer(0));
+ TestBean bean = (TestBean) em.getReference(TestBean.class, new Long(0));
bean.incrementCount();
assertNotNull(bean);
return new Event(this, "success");
@@ -46,7 +46,7 @@ public class JpaFlowManagedPersistenceIntegrationTests extends AbstractFlowManag
public void execute(RequestContext context, int expected) throws Exception {
assertSessionBound();
EntityManager em = (EntityManager) context.getFlowScope().get("persistenceContext");
- TestBean bean = (TestBean) em.getReference(TestBean.class, new Integer(0));
+ TestBean bean = (TestBean) em.getReference(TestBean.class, new Long(0));
assertEquals(expected, bean.getCount());
}
};
@@ -63,8 +63,7 @@ public class JpaFlowManagedPersistenceIntegrationTests extends AbstractFlowManag
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource);
factory.setPersistenceXmlLocation("classpath:org/springframework/webflow/persistence/persistence.xml");
- OpenJpaVendorAdapter openJpa = new OpenJpaVendorAdapter();
- factory.setJpaVendorAdapter(openJpa);
+ factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.afterPropertiesSet();
return factory.getObject();
}
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaPersistenceContextPropagationTests.java b/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaPersistenceContextPropagationTests.java
index 588d7920..baa7993b 100644
--- a/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaPersistenceContextPropagationTests.java
+++ b/spring-webflow/src/test/java/org/springframework/webflow/persistence/JpaPersistenceContextPropagationTests.java
@@ -1,11 +1,14 @@
package org.springframework.webflow.persistence;
+import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
-import org.springframework.orm.jpa.JpaTemplate;
+import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
+import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.webflow.execution.FlowExecutionListener;
@@ -16,8 +19,6 @@ public class JpaPersistenceContextPropagationTests extends AbstractPersistenceCo
private JpaFlowExecutionListener executionListener;
- private JpaTemplate jpaTemplate;
-
private int rowCount;
@Override
@@ -25,7 +26,6 @@ public class JpaPersistenceContextPropagationTests extends AbstractPersistenceCo
entityManagerFactory = getEntityManagerFactory(dataSource);
JpaTransactionManager tm = new JpaTransactionManager(entityManagerFactory);
executionListener = new JpaFlowExecutionListener(entityManagerFactory, tm);
- jpaTemplate = new JpaTemplate(entityManagerFactory);
rowCount = 1;
}
@@ -47,7 +47,8 @@ public class JpaPersistenceContextPropagationTests extends AbstractPersistenceCo
@Override
protected void assertCommitState(boolean insertRow, boolean isCommited) {
if (insertRow) {
- jpaTemplate.persist(new TestBean(rowCount++, "Keith Donald"));
+ EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
+ em.persist(new TestBean(rowCount++, "Keith Donald"));
}
if (!isCommited) {
assertEquals("Nothing should be committed yet", 1,
@@ -62,8 +63,7 @@ public class JpaPersistenceContextPropagationTests extends AbstractPersistenceCo
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource);
factory.setPersistenceXmlLocation("classpath:org/springframework/webflow/persistence/persistence.xml");
- OpenJpaVendorAdapter openJpa = new OpenJpaVendorAdapter();
- factory.setJpaVendorAdapter(openJpa);
+ factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.afterPropertiesSet();
return factory.getObject();
}
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/persistence/TestBean.hbm.xml b/spring-webflow/src/test/java/org/springframework/webflow/persistence/TestBean.hbm.xml
index 2b5a50fb..4660b23a 100644
--- a/spring-webflow/src/test/java/org/springframework/webflow/persistence/TestBean.hbm.xml
+++ b/spring-webflow/src/test/java/org/springframework/webflow/persistence/TestBean.hbm.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/persistence/TestBean.java b/spring-webflow/src/test/java/org/springframework/webflow/persistence/TestBean.java
index fd6caba0..f5d36e33 100644
--- a/spring-webflow/src/test/java/org/springframework/webflow/persistence/TestBean.java
+++ b/spring-webflow/src/test/java/org/springframework/webflow/persistence/TestBean.java
@@ -69,6 +69,10 @@ public class TestBean {
return count;
}
+ public void setCount(int count) {
+ this.count = count;
+ }
+
public void incrementCount() {
this.count++;
}
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/persistence/persistence.xml b/spring-webflow/src/test/java/org/springframework/webflow/persistence/persistence.xml
index b3a5d2af..88c49edb 100644
--- a/spring-webflow/src/test/java/org/springframework/webflow/persistence/persistence.xml
+++ b/spring-webflow/src/test/java/org/springframework/webflow/persistence/persistence.xml
@@ -11,6 +11,10 @@
true
+
+
+
+