Servlet/Portlet ApplicationContexts use a specific id based on servlet/portlet name; DefaultListableBeanFactory references are serializable now when initialized with an id; scoped proxies are serializable now, for web scopes as well as for singleton beans; injected request/session references are serializable proxies for the current request now
This commit is contained in:
parent
4ccb352aac
commit
266a65982d
|
@ -3,6 +3,16 @@ SPRING FRAMEWORK CHANGELOG
|
|||
http://www.springsource.org
|
||||
|
||||
|
||||
Changes in version 3.0.0.RC1 (2009-06-10)
|
||||
-----------------------------------------
|
||||
|
||||
* Servlet/Portlet ApplicationContexts use a specific id based on servlet/portlet name
|
||||
* DefaultListableBeanFactory references are serializable now when initialized with an id
|
||||
* scoped proxies are serializable now, for web scopes as well as for singleton beans
|
||||
* injected request/session references are serializable proxies for the current request now
|
||||
* ReloadableResourceBundleMessageSource correctly calculates filenames for all locales now
|
||||
|
||||
|
||||
Changes in version 3.0.0.M3 (2009-05-06)
|
||||
----------------------------------------
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.aop.scope;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
@ -32,7 +34,7 @@ import org.springframework.util.Assert;
|
|||
* @see org.springframework.beans.factory.BeanFactory#getBean
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroyScopedBean
|
||||
*/
|
||||
public class DefaultScopedObject implements ScopedObject {
|
||||
public class DefaultScopedObject implements ScopedObject, Serializable {
|
||||
|
||||
private final ConfigurableBeanFactory beanFactory;
|
||||
|
||||
|
@ -43,8 +45,6 @@ public class DefaultScopedObject implements ScopedObject {
|
|||
* Creates a new instance of the {@link DefaultScopedObject} class.
|
||||
* @param beanFactory the {@link ConfigurableBeanFactory} that holds the scoped target object
|
||||
* @param targetBeanName the name of the target bean
|
||||
* @throws IllegalArgumentException if either of the parameters is <code>null</code>; or
|
||||
* if the <code>targetBeanName</code> consists wholly of whitespace
|
||||
*/
|
||||
public DefaultScopedObject(ConfigurableBeanFactory beanFactory, String targetBeanName) {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2009 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.
|
||||
|
@ -157,29 +157,6 @@ public abstract class AbstractBeanFactoryBasedTargetSource
|
|||
this.beanFactory = other.beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces this object with a SingletonTargetSource on serialization.
|
||||
* Protected as otherwise it won't be invoked for subclasses.
|
||||
* (The <code>writeReplace()</code> method must be visible to the class
|
||||
* being serialized.)
|
||||
* <p>With this implementation of this method, there is no need to mark
|
||||
* non-serializable fields in this class or subclasses as transient.
|
||||
*/
|
||||
protected Object writeReplace() throws ObjectStreamException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Disconnecting TargetSource [" + this + "]");
|
||||
}
|
||||
try {
|
||||
// Create disconnected SingletonTargetSource.
|
||||
return new SingletonTargetSource(getTarget());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.error("Cannot get target for disconnecting TargetSource [" + this + "]", ex);
|
||||
throw new NotSerializableException(
|
||||
"Cannot get target for disconnecting TargetSource [" + this + "]: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
|
@ -23,8 +26,8 @@ import org.springframework.beans.factory.DisposableBean;
|
|||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
|
||||
/**
|
||||
* Base class for dynamic TargetSources that can create new prototype bean
|
||||
* instances to support a pooling or new-instance-per-invocation strategy.
|
||||
* Base class for dynamic {@link TargetSource} implementations that create new prototype
|
||||
* bean instances to support a pooling or new-instance-per-invocation strategy.
|
||||
*
|
||||
* <p>Such TargetSources must run in a {@link BeanFactory}, as it needs to
|
||||
* call the <code>getBean</code> method to create a new prototype instance.
|
||||
|
@ -83,4 +86,32 @@ public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFac
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Serialization support
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Replaces this object with a SingletonTargetSource on serialization.
|
||||
* Protected as otherwise it won't be invoked for subclasses.
|
||||
* (The <code>writeReplace()</code> method must be visible to the class
|
||||
* being serialized.)
|
||||
* <p>With this implementation of this method, there is no need to mark
|
||||
* non-serializable fields in this class or subclasses as transient.
|
||||
*/
|
||||
protected Object writeReplace() throws ObjectStreamException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Disconnecting TargetSource [" + this + "]");
|
||||
}
|
||||
try {
|
||||
// Create disconnected SingletonTargetSource.
|
||||
return new SingletonTargetSource(getTarget());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.error("Cannot get target for disconnecting TargetSource [" + this + "]", ex);
|
||||
throw new NotSerializableException(
|
||||
"Cannot get target for disconnecting TargetSource [" + this + "]: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,9 +16,7 @@
|
|||
|
||||
package test.util;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -28,8 +26,8 @@ import java.io.ObjectOutputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import test.beans.TestBean;
|
||||
|
||||
/**
|
||||
|
@ -41,13 +39,13 @@ import test.beans.TestBean;
|
|||
* @author Chris Beams
|
||||
*/
|
||||
public final class SerializationTestUtils {
|
||||
|
||||
|
||||
public static void testSerialization(Object o) throws IOException {
|
||||
OutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
}
|
||||
|
||||
|
||||
public static boolean isSerializable(Object o) throws IOException {
|
||||
try {
|
||||
testSerialization(o);
|
||||
|
@ -57,7 +55,7 @@ public final class SerializationTestUtils {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
|
@ -69,30 +67,30 @@ public final class SerializationTestUtils {
|
|||
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(is);
|
||||
Object o2 = ois.readObject();
|
||||
|
||||
return o2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test(expected=NotSerializableException.class)
|
||||
public void testWithNonSerializableObject() throws IOException {
|
||||
TestBean o = new TestBean();
|
||||
assertFalse(o instanceof Serializable);
|
||||
assertFalse(isSerializable(o));
|
||||
|
||||
|
||||
testSerialization(o);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWithSerializableObject() throws Exception {
|
||||
int x = 5;
|
||||
int y = 10;
|
||||
Point p = new Point(x, y);
|
||||
assertTrue(p instanceof Serializable);
|
||||
|
||||
|
||||
testSerialization(p);
|
||||
|
||||
|
||||
assertTrue(isSerializable(p));
|
||||
|
||||
|
||||
Point p2 = (Point) serializeAndDeserialize(p);
|
||||
assertNotSame(p, p2);
|
||||
assertEquals(x, (int) p2.getX());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 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.
|
||||
|
@ -236,6 +236,9 @@ public abstract class AbstractFactoryBean<T>
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reflective InvocationHandler for lazy access to the actual singleton object.
|
||||
*/
|
||||
private class EarlySingletonInvocationHandler implements InvocationHandler {
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
|
|
|
@ -868,12 +868,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
if (mbd.isSingleton() || mbd.isPrototype()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Bean name '" + beanName + "' does not correspond to an object in a Scope");
|
||||
"Bean name '" + beanName + "' does not correspond to an object in a mutable scope");
|
||||
}
|
||||
String scopeName = mbd.getScope();
|
||||
Scope scope = this.scopes.get(scopeName);
|
||||
if (scope == null) {
|
||||
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
|
||||
throw new IllegalStateException("No Scope SPI registered for scope '" + scopeName + "'");
|
||||
}
|
||||
Object bean = scope.remove(beanName);
|
||||
if (bean != null) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,13 +17,18 @@
|
|||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
|
@ -123,4 +128,55 @@ abstract class AutowireUtils {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given autowiring value against the given required type,
|
||||
* e.g. an {@link ObjectFactory} value to its actual object result.
|
||||
* @param autowiringValue the value to resolve
|
||||
* @param requiredType the type to assign the result to
|
||||
* @return the resolved value
|
||||
*/
|
||||
public static Object resolveAutowiringValue(Object autowiringValue, Class requiredType) {
|
||||
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue) &&
|
||||
autowiringValue instanceof Serializable && requiredType.isInterface()) {
|
||||
autowiringValue = Proxy.newProxyInstance(
|
||||
requiredType.getClassLoader(), new Class[] {requiredType},
|
||||
new ObjectFactoryDelegatingInvocationHandler((ObjectFactory) autowiringValue));
|
||||
}
|
||||
return autowiringValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reflective InvocationHandler for lazy access to the current target object.
|
||||
*/
|
||||
private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {
|
||||
|
||||
private final ObjectFactory objectFactory;
|
||||
|
||||
public ObjectFactoryDelegatingInvocationHandler(ObjectFactory objectFactory) {
|
||||
this.objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String methodName = method.getName();
|
||||
if (methodName.equals("equals")) {
|
||||
// Only consider equal when proxies are identical.
|
||||
return (proxy == args[0]);
|
||||
}
|
||||
else if (methodName.equals("hashCode")) {
|
||||
// Use hashCode of proxy.
|
||||
return System.identityHashCode(proxy);
|
||||
}
|
||||
else if (methodName.equals("toString")) {
|
||||
return this.objectFactory.toString();
|
||||
}
|
||||
try {
|
||||
return method.invoke(this.objectFactory.getObject(), args);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
@ -81,7 +85,14 @@ import org.springframework.util.StringUtils;
|
|||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
*/
|
||||
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
|
||||
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
|
||||
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
|
||||
|
||||
/** Map from serialized id to factory instance */
|
||||
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
|
||||
new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>();
|
||||
|
||||
/** Optional id for this factory, for serialization purposes */
|
||||
private String serializationId;
|
||||
|
||||
/** Whether to allow re-registration of a different definition with the same name */
|
||||
private boolean allowBeanDefinitionOverriding = true;
|
||||
|
@ -127,6 +138,20 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify an id for serialization purposes, allowing this BeanFactory to be
|
||||
* deserialized from this id back into the BeanFactory object, if needed.
|
||||
*/
|
||||
public void setSerializationId(String serializationId) {
|
||||
if (serializationId != null) {
|
||||
serializableFactories.put(serializationId, new WeakReference<DefaultListableBeanFactory>(this));
|
||||
}
|
||||
else if (this.serializationId != null) {
|
||||
serializableFactories.remove(this.serializationId);
|
||||
}
|
||||
this.serializationId = serializationId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether it should be allowed to override bean definitions by registering
|
||||
* a different definition with the same name, automatically replacing the former.
|
||||
|
@ -724,9 +749,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
for (Class autowiringType : this.resolvableDependencies.keySet()) {
|
||||
if (autowiringType.isAssignableFrom(requiredType)) {
|
||||
Object autowiringValue = this.resolvableDependencies.get(autowiringType);
|
||||
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
|
||||
autowiringValue = ((ObjectFactory) autowiringValue).getObject();
|
||||
}
|
||||
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
|
||||
if (requiredType.isInstance(autowiringValue)) {
|
||||
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
|
||||
break;
|
||||
|
@ -824,4 +847,46 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Serialization support
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
protected Object writeReplace() throws ObjectStreamException {
|
||||
if (this.serializationId != null) {
|
||||
return new SerializedBeanFactoryReference(this.serializationId);
|
||||
}
|
||||
else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Minimal id reference to the factory.
|
||||
* Resolved to the actual factory instance on deserialization.
|
||||
*/
|
||||
private static class SerializedBeanFactoryReference implements Serializable {
|
||||
|
||||
private final String id;
|
||||
|
||||
public SerializedBeanFactoryReference(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
Reference ref = serializableFactories.get(this.id);
|
||||
if (ref == null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot deserialize BeanFactory with id " + this.id + ": no factory registered for this id");
|
||||
}
|
||||
Object result = ref.get();
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot deserialize BeanFactory with id " + this.id + ": factory has been garbage-collected");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 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.
|
||||
|
@ -65,6 +65,11 @@ public interface ConfigurableApplicationContext extends ApplicationContext, Life
|
|||
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
|
||||
|
||||
|
||||
/**
|
||||
* Set the unique id of this application context.
|
||||
*/
|
||||
void setId(String id);
|
||||
|
||||
/**
|
||||
* Set the parent of this application context.
|
||||
* <p>Note that the parent shouldn't be changed: It should only be set outside
|
||||
|
|
|
@ -382,7 +382,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
|
||||
catch (BeansException ex) {
|
||||
// Destroy already created singletons to avoid dangling resources.
|
||||
beanFactory.destroySingletons();
|
||||
destroyBeans();
|
||||
|
||||
// Reset 'active' flag.
|
||||
cancelRefresh(ex);
|
||||
|
@ -794,7 +794,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
* destroys the singletons in the bean factory of this application context.
|
||||
* <p>Called by both <code>close()</code> and a JVM shutdown hook, if any.
|
||||
* @see org.springframework.context.event.ContextClosedEvent
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
|
||||
* @see #destroyBeans()
|
||||
* @see #close()
|
||||
* @see #registerShutdownHook()
|
||||
*/
|
||||
|
@ -803,6 +803,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Closing " + this);
|
||||
}
|
||||
|
||||
try {
|
||||
// Publish shutdown event.
|
||||
publishEvent(new ContextClosedEvent(this));
|
||||
|
@ -810,15 +811,19 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
catch (Throwable ex) {
|
||||
logger.error("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
|
||||
}
|
||||
|
||||
// Stop all Lifecycle beans, to avoid delays during individual destruction.
|
||||
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
|
||||
for (String beanName : new LinkedHashSet<String>(lifecycleBeans.keySet())) {
|
||||
doStop(lifecycleBeans, beanName);
|
||||
}
|
||||
|
||||
// Destroy all cached singletons in the context's BeanFactory.
|
||||
destroyBeans();
|
||||
|
||||
// Close the state of this context itself.
|
||||
closeBeanFactory();
|
||||
|
||||
onClose();
|
||||
synchronized (this.activeMonitor) {
|
||||
this.active = false;
|
||||
|
|
|
@ -122,6 +122,7 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
|
|||
}
|
||||
try {
|
||||
DefaultListableBeanFactory beanFactory = createBeanFactory();
|
||||
beanFactory.setSerializationId(getId());
|
||||
customizeBeanFactory(beanFactory);
|
||||
loadBeanDefinitions(beanFactory);
|
||||
synchronized (this.beanFactoryMonitor) {
|
||||
|
@ -134,9 +135,18 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelRefresh(BeansException ex) {
|
||||
synchronized (this.beanFactoryMonitor) {
|
||||
this.beanFactory.setSerializationId(null);
|
||||
}
|
||||
super.cancelRefresh(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void closeBeanFactory() {
|
||||
synchronized (this.beanFactoryMonitor) {
|
||||
this.beanFactory.setSerializationId(null);
|
||||
this.beanFactory = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
|||
*/
|
||||
public GenericApplicationContext() {
|
||||
this.beanFactory = new DefaultListableBeanFactory();
|
||||
this.beanFactory.setSerializationId(getId());
|
||||
this.beanFactory.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer());
|
||||
this.beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
}
|
||||
|
@ -149,6 +150,12 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
|||
this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
super.setId(id);
|
||||
this.beanFactory.setSerializationId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a ResourceLoader to use for this context. If set, the context will
|
||||
* delegate all <code>getResource</code> calls to the given ResourceLoader.
|
||||
|
@ -219,11 +226,12 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
|||
}
|
||||
|
||||
/**
|
||||
* Do nothing: We hold a single internal BeanFactory that will never
|
||||
* Not much to do: We hold a single internal BeanFactory that will never
|
||||
* get released.
|
||||
*/
|
||||
@Override
|
||||
protected final void closeBeanFactory() {
|
||||
this.beanFactory.setSerializationId(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
|
||||
package org.springframework.aop.scope;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.ITestBean;
|
||||
import org.springframework.beans.TestBean;
|
||||
|
@ -31,6 +31,7 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
|||
import org.springframework.beans.factory.xml.XmlBeanFactory;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.SerializationTestUtils;
|
||||
|
||||
/**
|
||||
* @author Rob Harrop
|
||||
|
@ -82,6 +83,7 @@ public class ScopedProxyTests {
|
|||
@Test
|
||||
public void testJdkScopedProxy() throws Exception {
|
||||
XmlBeanFactory bf = new XmlBeanFactory(TESTBEAN_CONTEXT);
|
||||
bf.setSerializationId("X");
|
||||
SimpleMapScope scope = new SimpleMapScope();
|
||||
bf.registerScope("request", scope);
|
||||
|
||||
|
@ -91,14 +93,26 @@ public class ScopedProxyTests {
|
|||
assertTrue(bean instanceof ScopedObject);
|
||||
ScopedObject scoped = (ScopedObject) bean;
|
||||
assertEquals(TestBean.class, scoped.getTargetObject().getClass());
|
||||
bean.setAge(101);
|
||||
|
||||
assertTrue(scope.getMap().containsKey("testBeanTarget"));
|
||||
assertEquals(TestBean.class, scope.getMap().get("testBeanTarget").getClass());
|
||||
|
||||
ITestBean deserialized = (ITestBean) SerializationTestUtils.serializeAndDeserialize(bean);
|
||||
assertNotNull(deserialized);
|
||||
assertTrue(AopUtils.isJdkDynamicProxy(deserialized));
|
||||
assertEquals(101, bean.getAge());
|
||||
assertTrue(deserialized instanceof ScopedObject);
|
||||
ScopedObject scopedDeserialized = (ScopedObject) deserialized;
|
||||
assertEquals(TestBean.class, scopedDeserialized.getTargetObject().getClass());
|
||||
|
||||
bf.setSerializationId(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCglibScopedProxy() {
|
||||
public void testCglibScopedProxy() throws Exception {
|
||||
XmlBeanFactory bf = new XmlBeanFactory(LIST_CONTEXT);
|
||||
bf.setSerializationId("Y");
|
||||
SimpleMapScope scope = new SimpleMapScope();
|
||||
bf.registerScope("request", scope);
|
||||
|
||||
|
@ -107,9 +121,20 @@ public class ScopedProxyTests {
|
|||
assertTrue(tb.getFriends() instanceof ScopedObject);
|
||||
ScopedObject scoped = (ScopedObject) tb.getFriends();
|
||||
assertEquals(ArrayList.class, scoped.getTargetObject().getClass());
|
||||
tb.getFriends().add("myFriend");
|
||||
|
||||
assertTrue(scope.getMap().containsKey("scopedTarget.scopedList"));
|
||||
assertEquals(ArrayList.class, scope.getMap().get("scopedTarget.scopedList").getClass());
|
||||
|
||||
ArrayList deserialized = (ArrayList) SerializationTestUtils.serializeAndDeserialize(tb.getFriends());
|
||||
assertNotNull(deserialized);
|
||||
assertTrue(AopUtils.isCglibProxy(deserialized));
|
||||
assertTrue(deserialized.contains("myFriend"));
|
||||
assertTrue(deserialized instanceof ScopedObject);
|
||||
ScopedObject scopedDeserialized = (ScopedObject) deserialized;
|
||||
assertEquals(ArrayList.class, scopedDeserialized.getTargetObject().getClass());
|
||||
|
||||
bf.setSerializationId(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2009 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,16 +16,16 @@
|
|||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import example.scannable.FooService;
|
||||
import example.scannable.ScopedProxyTestBean;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.config.SimpleMapScope;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import example.scannable.FooService;
|
||||
import example.scannable.ScopedProxyTestBean;
|
||||
import org.springframework.util.SerializationTestUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
|
@ -54,7 +54,7 @@ public class ComponentScanParserScopedProxyTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testInterfacesScopedProxy() {
|
||||
public void testInterfacesScopedProxy() throws Exception {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/context/annotation/scopedProxyInterfacesTests.xml");
|
||||
context.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
||||
|
@ -62,16 +62,26 @@ public class ComponentScanParserScopedProxyTests {
|
|||
FooService bean = (FooService) context.getBean("scopedProxyTestBean");
|
||||
// should be dynamic proxy
|
||||
assertTrue(AopUtils.isJdkDynamicProxy(bean));
|
||||
// test serializability
|
||||
assertEquals("bar", bean.foo(1));
|
||||
FooService deserialized = (FooService) SerializationTestUtils.serializeAndDeserialize(bean);
|
||||
assertNotNull(deserialized);
|
||||
assertEquals("bar", deserialized.foo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTargetClassScopedProxy() {
|
||||
public void testTargetClassScopedProxy() throws Exception {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/context/annotation/scopedProxyTargetClassTests.xml");
|
||||
context.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
||||
ScopedProxyTestBean bean = (ScopedProxyTestBean) context.getBean("scopedProxyTestBean");
|
||||
// should be a class-based proxy
|
||||
assertTrue(AopUtils.isCglibProxy(bean));
|
||||
// test serializability
|
||||
assertEquals("bar", bean.foo(1));
|
||||
ScopedProxyTestBean deserialized = (ScopedProxyTestBean) SerializationTestUtils.serializeAndDeserialize(bean);
|
||||
assertNotNull(deserialized);
|
||||
assertEquals("bar", deserialized.foo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
/*
|
||||
* The Spring Framework is published under the terms
|
||||
* of the Apache Software License.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -13,20 +23,14 @@ import java.io.NotSerializableException;
|
|||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.beans.TestBean;
|
||||
|
||||
/**
|
||||
* Utilities for testing serializability of objects.
|
||||
* Exposes static methods for use in other test cases.
|
||||
* Extends TestCase only to test itself.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public class SerializationTestUtils extends TestCase {
|
||||
public class SerializationTestUtils {
|
||||
|
||||
public static void testSerialization(Object o) throws IOException {
|
||||
OutputStream baos = new ByteArrayOutputStream();
|
||||
|
@ -55,43 +59,7 @@ public class SerializationTestUtils extends TestCase {
|
|||
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(is);
|
||||
Object o2 = ois.readObject();
|
||||
|
||||
return o2;
|
||||
}
|
||||
|
||||
public SerializationTestUtils(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public void testWithNonSerializableObject() throws IOException {
|
||||
TestBean o = new TestBean();
|
||||
assertFalse(o instanceof Serializable);
|
||||
|
||||
assertFalse(isSerializable(o));
|
||||
|
||||
try {
|
||||
testSerialization(o);
|
||||
fail();
|
||||
}
|
||||
catch (NotSerializableException ex) {
|
||||
// Ok
|
||||
}
|
||||
}
|
||||
|
||||
public void testWithSerializableObject() throws Exception {
|
||||
int x = 5;
|
||||
int y = 10;
|
||||
Point p = new Point(x, y);
|
||||
assertTrue(p instanceof Serializable);
|
||||
|
||||
testSerialization(p);
|
||||
|
||||
assertTrue(isSerializable(p));
|
||||
|
||||
Point p2 = (Point) serializeAndDeserialize(p);
|
||||
assertNotSame(p, p2);
|
||||
assertEquals(x, (int) p2.getX());
|
||||
assertEquals(y, (int) p2.getY());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
|
||||
<bean id="testBean" class="test.beans.TestBean"/>
|
||||
|
||||
<bean id="singletonScoped" class="test.beans.TestBean">
|
||||
<aop:scoped-proxy/>
|
||||
<property name="name" value="Rob Harrop"/>
|
||||
</bean>
|
||||
|
||||
<bean id="requestScoped" class="test.beans.TestBean" scope="request">
|
||||
<aop:scoped-proxy/>
|
||||
<property name="name" value="Rob Harrop"/>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,23 +17,24 @@
|
|||
package org.springframework.aop.config;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.util.ClassUtils.convertClassNameToResourcePath;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import test.beans.ITestBean;
|
||||
import test.beans.TestBean;
|
||||
import test.util.SerializationTestUtils;
|
||||
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.context.support.XmlWebApplicationContext;
|
||||
|
||||
import test.beans.ITestBean;
|
||||
import test.beans.TestBean;
|
||||
|
||||
/**
|
||||
* Integration tests for scoped proxy use in conjunction with aop: namespace.
|
||||
* Deemed an integration test because .web mocks and application contexts are required.
|
||||
|
@ -47,7 +48,7 @@ import test.beans.TestBean;
|
|||
public final class AopNamespaceHandlerScopeIntegrationTests {
|
||||
|
||||
private static final String CLASSNAME = AopNamespaceHandlerScopeIntegrationTests.class.getName();
|
||||
private static final String CONTEXT = format("classpath:%s-context.xml", convertClassNameToResourcePath(CLASSNAME));
|
||||
private static final String CONTEXT = format("classpath:%s-context.xml", ClassUtils.convertClassNameToResourcePath(CLASSNAME));
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
|
@ -59,6 +60,20 @@ public final class AopNamespaceHandlerScopeIntegrationTests {
|
|||
this.context = wac;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingletonScoping() throws Exception {
|
||||
ITestBean scoped = (ITestBean) this.context.getBean("singletonScoped");
|
||||
assertTrue("Should be AOP proxy", AopUtils.isAopProxy(scoped));
|
||||
assertTrue("Should be target class proxy", scoped instanceof TestBean);
|
||||
String rob = "Rob Harrop";
|
||||
String bram = "Bram Smeets";
|
||||
assertEquals(rob, scoped.getName());
|
||||
scoped.setName(bram);
|
||||
assertEquals(bram, scoped.getName());
|
||||
ITestBean deserialized = (ITestBean) SerializationTestUtils.serializeAndDeserialize(scoped);
|
||||
assertEquals(bram, deserialized.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestScoping() throws Exception {
|
||||
MockHttpServletRequest oldRequest = new MockHttpServletRequest();
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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 test.util;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import test.beans.TestBean;
|
||||
|
||||
/**
|
||||
* Utilities for testing serializability of objects.
|
||||
* Exposes static methods for use in other test cases.
|
||||
* Contains {@link org.junit.Test} methods to test itself.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public final class SerializationTestUtils {
|
||||
|
||||
public static void testSerialization(Object o) throws IOException {
|
||||
OutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
}
|
||||
|
||||
public static boolean isSerializable(Object o) throws IOException {
|
||||
try {
|
||||
testSerialization(o);
|
||||
return true;
|
||||
}
|
||||
catch (NotSerializableException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
oos.flush();
|
||||
baos.flush();
|
||||
byte[] bytes = baos.toByteArray();
|
||||
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(is);
|
||||
Object o2 = ois.readObject();
|
||||
return o2;
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=NotSerializableException.class)
|
||||
public void testWithNonSerializableObject() throws IOException {
|
||||
TestBean o = new TestBean();
|
||||
assertFalse(o instanceof Serializable);
|
||||
assertFalse(isSerializable(o));
|
||||
|
||||
testSerialization(o);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithSerializableObject() throws Exception {
|
||||
int x = 5;
|
||||
int y = 10;
|
||||
Point p = new Point(x, y);
|
||||
assertTrue(p instanceof Serializable);
|
||||
|
||||
testSerialization(p);
|
||||
|
||||
assertTrue(isSerializable(p));
|
||||
|
||||
Point p2 = (Point) serializeAndDeserialize(p);
|
||||
assertNotSame(p, p2);
|
||||
assertEquals(x, (int) p2.getX());
|
||||
assertEquals(y, (int) p2.getY());
|
||||
}
|
||||
|
||||
}
|
|
@ -340,6 +340,7 @@ public abstract class FrameworkPortlet extends GenericPortletBean
|
|||
|
||||
ConfigurablePortletApplicationContext pac =
|
||||
(ConfigurablePortletApplicationContext) BeanUtils.instantiateClass(getContextClass());
|
||||
pac.setId(getPortletContext().getPortletContextName() + "." + getPortletName());
|
||||
pac.setParent(parent);
|
||||
pac.setPortletContext(getPortletContext());
|
||||
pac.setPortletConfig(getPortletConfig());
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.web.portlet.context;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
|
@ -120,24 +121,8 @@ public abstract class PortletApplicationContextUtils {
|
|||
pc.setAttribute(PortletContextScope.class.getName(), appScope);
|
||||
}
|
||||
|
||||
beanFactory.registerResolvableDependency(PortletRequest.class, new ObjectFactory<PortletRequest>() {
|
||||
public PortletRequest getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof PortletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a portlet request");
|
||||
}
|
||||
return ((PortletRequestAttributes) requestAttr).getRequest();
|
||||
}
|
||||
});
|
||||
beanFactory.registerResolvableDependency(PortletSession.class, new ObjectFactory<PortletSession>() {
|
||||
public PortletSession getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof PortletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a portlet request");
|
||||
}
|
||||
return ((PortletRequestAttributes) requestAttr).getRequest().getPortletSession();
|
||||
}
|
||||
});
|
||||
beanFactory.registerResolvableDependency(PortletRequest.class, new RequestObjectFactory());
|
||||
beanFactory.registerResolvableDependency(PortletSession.class, new SessionObjectFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -197,4 +182,44 @@ public abstract class PortletApplicationContextUtils {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory that exposes the current request object on demand.
|
||||
*/
|
||||
private static class RequestObjectFactory implements ObjectFactory<PortletRequest>, Serializable {
|
||||
|
||||
public PortletRequest getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof PortletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a portlet request");
|
||||
}
|
||||
return ((PortletRequestAttributes) requestAttr).getRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Current PortletRequest";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory that exposes the current session object on demand.
|
||||
*/
|
||||
private static class SessionObjectFactory implements ObjectFactory<PortletSession>, Serializable {
|
||||
|
||||
public PortletSession getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof PortletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a portlet request");
|
||||
}
|
||||
return ((PortletRequestAttributes) requestAttr).getRequest().getPortletSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Current PortletSession";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -416,6 +416,7 @@ public abstract class FrameworkServlet extends HttpServletBean
|
|||
|
||||
ConfigurableWebApplicationContext wac =
|
||||
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());
|
||||
wac.setId(getServletContext().getServletContextName() + "." + getServletName());
|
||||
wac.setParent(parent);
|
||||
wac.setServletContext(getServletContext());
|
||||
wac.setServletConfig(getServletConfig());
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Utilities for testing serializability of objects.
|
||||
* Exposes static methods for use in other test cases.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public class SerializationTestUtils {
|
||||
|
||||
public static void testSerialization(Object o) throws IOException {
|
||||
OutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
}
|
||||
|
||||
public static boolean isSerializable(Object o) throws IOException {
|
||||
try {
|
||||
testSerialization(o);
|
||||
return true;
|
||||
}
|
||||
catch (NotSerializableException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
oos.flush();
|
||||
baos.flush();
|
||||
byte[] bytes = baos.toByteArray();
|
||||
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(is);
|
||||
Object o2 = ois.readObject();
|
||||
return o2;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@ package org.springframework.web.servlet.mvc.annotation;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -72,6 +73,7 @@ import org.springframework.stereotype.Controller;
|
|||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.SerializationTestUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
|
@ -524,7 +526,7 @@ public class ServletAnnotationControllerTests {
|
|||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.setServletContext(servletContext);
|
||||
RootBeanDefinition bd = new RootBeanDefinition(MyParameterDispatchingController.class);
|
||||
bd.setScope(WebApplicationContext.SCOPE_REQUEST);
|
||||
//bd.setScope(WebApplicationContext.SCOPE_REQUEST);
|
||||
wac.registerBeanDefinition("controller", bd);
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(wac);
|
||||
wac.getBeanFactory().registerResolvableDependency(ServletConfig.class, servletConfig);
|
||||
|
@ -541,8 +543,8 @@ public class ServletAnnotationControllerTests {
|
|||
assertEquals("myView", response.getContentAsString());
|
||||
assertSame(servletContext, request.getAttribute("servletContext"));
|
||||
assertSame(servletConfig, request.getAttribute("servletConfig"));
|
||||
assertSame(session, request.getAttribute("session"));
|
||||
assertSame(request, request.getAttribute("request"));
|
||||
assertSame(session.getId(), request.getAttribute("sessionId"));
|
||||
assertSame(request.getRequestURI(), request.getAttribute("requestUri"));
|
||||
|
||||
request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do");
|
||||
response = new MockHttpServletResponse();
|
||||
|
@ -551,8 +553,8 @@ public class ServletAnnotationControllerTests {
|
|||
assertEquals("myView", response.getContentAsString());
|
||||
assertSame(servletContext, request.getAttribute("servletContext"));
|
||||
assertSame(servletConfig, request.getAttribute("servletConfig"));
|
||||
assertSame(session, request.getAttribute("session"));
|
||||
assertSame(request, request.getAttribute("request"));
|
||||
assertSame(session.getId(), request.getAttribute("sessionId"));
|
||||
assertSame(request.getRequestURI(), request.getAttribute("requestUri"));
|
||||
|
||||
request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do");
|
||||
request.addParameter("view", "other");
|
||||
|
@ -572,6 +574,11 @@ public class ServletAnnotationControllerTests {
|
|||
response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("mySurpriseView", response.getContentAsString());
|
||||
|
||||
MyParameterDispatchingController deserialized = (MyParameterDispatchingController)
|
||||
SerializationTestUtils.serializeAndDeserialize(servlet.getWebApplicationContext().getBean("controller"));
|
||||
assertNotNull(deserialized.request);
|
||||
assertNotNull(deserialized.session);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1265,13 +1272,13 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
@Controller
|
||||
@RequestMapping("/myPath.do")
|
||||
private static class MyParameterDispatchingController {
|
||||
private static class MyParameterDispatchingController implements Serializable {
|
||||
|
||||
@Autowired
|
||||
private ServletContext servletContext;
|
||||
private transient ServletContext servletContext;
|
||||
|
||||
@Autowired
|
||||
private ServletConfig servletConfig;
|
||||
private transient ServletConfig servletConfig;
|
||||
|
||||
@Autowired
|
||||
private HttpSession session;
|
||||
|
@ -1288,8 +1295,8 @@ public class ServletAnnotationControllerTests {
|
|||
response.getWriter().write("myView");
|
||||
request.setAttribute("servletContext", this.servletContext);
|
||||
request.setAttribute("servletConfig", this.servletConfig);
|
||||
request.setAttribute("session", this.session);
|
||||
request.setAttribute("request", this.request);
|
||||
request.setAttribute("sessionId", this.session.getId());
|
||||
request.setAttribute("requestUri", this.request.getRequestURI());
|
||||
}
|
||||
|
||||
@RequestMapping(params = {"view", "!lang"})
|
||||
|
|
|
@ -247,6 +247,7 @@ public class ContextLoader {
|
|||
|
||||
ConfigurableWebApplicationContext wac =
|
||||
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
|
||||
wac.setId(servletContext.getServletContextName());
|
||||
wac.setParent(parent);
|
||||
wac.setServletContext(servletContext);
|
||||
wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM));
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.web.context.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
|
@ -150,25 +151,8 @@ public abstract class WebApplicationContextUtils {
|
|||
sc.setAttribute(ServletContextScope.class.getName(), appScope);
|
||||
}
|
||||
|
||||
beanFactory.registerResolvableDependency(ServletRequest.class, new ObjectFactory<ServletRequest>() {
|
||||
public ServletRequest getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof ServletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a servlet request");
|
||||
}
|
||||
return ((ServletRequestAttributes) requestAttr).getRequest();
|
||||
}
|
||||
});
|
||||
beanFactory.registerResolvableDependency(HttpSession.class, new ObjectFactory<HttpSession>() {
|
||||
public HttpSession getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof ServletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a servlet request");
|
||||
}
|
||||
return ((ServletRequestAttributes) requestAttr).getRequest().getSession();
|
||||
}
|
||||
});
|
||||
|
||||
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
|
||||
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
|
||||
if (jsfPresent) {
|
||||
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
|
||||
}
|
||||
|
@ -237,6 +221,46 @@ public abstract class WebApplicationContextUtils {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory that exposes the current request object on demand.
|
||||
*/
|
||||
private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
|
||||
|
||||
public ServletRequest getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof ServletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a servlet request");
|
||||
}
|
||||
return ((ServletRequestAttributes) requestAttr).getRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Current HttpServletRequest";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory that exposes the current session object on demand.
|
||||
*/
|
||||
private static class SessionObjectFactory implements ObjectFactory<HttpSession>, Serializable {
|
||||
|
||||
public HttpSession getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof ServletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a servlet request");
|
||||
}
|
||||
return ((ServletRequestAttributes) requestAttr).getRequest().getSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Current HttpSession";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid hard-coded JSF dependency.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue