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 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 + + + +