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
|
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)
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.aop.scope;
|
package org.springframework.aop.scope;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.util.Assert;
|
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.BeanFactory#getBean
|
||||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroyScopedBean
|
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroyScopedBean
|
||||||
*/
|
*/
|
||||||
public class DefaultScopedObject implements ScopedObject {
|
public class DefaultScopedObject implements ScopedObject, Serializable {
|
||||||
|
|
||||||
private final ConfigurableBeanFactory beanFactory;
|
private final ConfigurableBeanFactory beanFactory;
|
||||||
|
|
||||||
|
@ -43,8 +45,6 @@ public class DefaultScopedObject implements ScopedObject {
|
||||||
* Creates a new instance of the {@link DefaultScopedObject} class.
|
* Creates a new instance of the {@link DefaultScopedObject} class.
|
||||||
* @param beanFactory the {@link ConfigurableBeanFactory} that holds the scoped target object
|
* @param beanFactory the {@link ConfigurableBeanFactory} that holds the scoped target object
|
||||||
* @param targetBeanName the name of the target bean
|
* @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) {
|
public DefaultScopedObject(ConfigurableBeanFactory beanFactory, String targetBeanName) {
|
||||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
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
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package org.springframework.aop.target;
|
package org.springframework.aop.target;
|
||||||
|
|
||||||
|
import java.io.NotSerializableException;
|
||||||
|
import java.io.ObjectStreamException;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
@ -23,8 +26,8 @@ import org.springframework.beans.factory.DisposableBean;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for dynamic TargetSources that can create new prototype bean
|
* Base class for dynamic {@link TargetSource} implementations that create new prototype
|
||||||
* instances to support a pooling or new-instance-per-invocation strategy.
|
* 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
|
* <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.
|
* 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,9 +16,7 @@
|
||||||
|
|
||||||
package test.util;
|
package test.util;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import java.awt.*;
|
||||||
|
|
||||||
import java.awt.Point;
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -28,8 +26,8 @@ import java.io.ObjectOutputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import test.beans.TestBean;
|
import test.beans.TestBean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,13 +39,13 @@ import test.beans.TestBean;
|
||||||
* @author Chris Beams
|
* @author Chris Beams
|
||||||
*/
|
*/
|
||||||
public final class SerializationTestUtils {
|
public final class SerializationTestUtils {
|
||||||
|
|
||||||
public static void testSerialization(Object o) throws IOException {
|
public static void testSerialization(Object o) throws IOException {
|
||||||
OutputStream baos = new ByteArrayOutputStream();
|
OutputStream baos = new ByteArrayOutputStream();
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
oos.writeObject(o);
|
oos.writeObject(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSerializable(Object o) throws IOException {
|
public static boolean isSerializable(Object o) throws IOException {
|
||||||
try {
|
try {
|
||||||
testSerialization(o);
|
testSerialization(o);
|
||||||
|
@ -57,7 +55,7 @@ public final class SerializationTestUtils {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException {
|
public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
@ -69,30 +67,30 @@ public final class SerializationTestUtils {
|
||||||
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
||||||
ObjectInputStream ois = new ObjectInputStream(is);
|
ObjectInputStream ois = new ObjectInputStream(is);
|
||||||
Object o2 = ois.readObject();
|
Object o2 = ois.readObject();
|
||||||
|
|
||||||
return o2;
|
return o2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test(expected=NotSerializableException.class)
|
@Test(expected=NotSerializableException.class)
|
||||||
public void testWithNonSerializableObject() throws IOException {
|
public void testWithNonSerializableObject() throws IOException {
|
||||||
TestBean o = new TestBean();
|
TestBean o = new TestBean();
|
||||||
assertFalse(o instanceof Serializable);
|
assertFalse(o instanceof Serializable);
|
||||||
assertFalse(isSerializable(o));
|
assertFalse(isSerializable(o));
|
||||||
|
|
||||||
testSerialization(o);
|
testSerialization(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWithSerializableObject() throws Exception {
|
public void testWithSerializableObject() throws Exception {
|
||||||
int x = 5;
|
int x = 5;
|
||||||
int y = 10;
|
int y = 10;
|
||||||
Point p = new Point(x, y);
|
Point p = new Point(x, y);
|
||||||
assertTrue(p instanceof Serializable);
|
assertTrue(p instanceof Serializable);
|
||||||
|
|
||||||
testSerialization(p);
|
testSerialization(p);
|
||||||
|
|
||||||
assertTrue(isSerializable(p));
|
assertTrue(isSerializable(p));
|
||||||
|
|
||||||
Point p2 = (Point) serializeAndDeserialize(p);
|
Point p2 = (Point) serializeAndDeserialize(p);
|
||||||
assertNotSame(p, p2);
|
assertNotSame(p, p2);
|
||||||
assertEquals(x, (int) p2.getX());
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 {
|
private class EarlySingletonInvocationHandler implements InvocationHandler {
|
||||||
|
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
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);
|
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||||
if (mbd.isSingleton() || mbd.isPrototype()) {
|
if (mbd.isSingleton() || mbd.isPrototype()) {
|
||||||
throw new IllegalArgumentException(
|
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();
|
String scopeName = mbd.getScope();
|
||||||
Scope scope = this.scopes.get(scopeName);
|
Scope scope = this.scopes.get(scopeName);
|
||||||
if (scope == null) {
|
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);
|
Object bean = scope.remove(beanName);
|
||||||
if (bean != null) {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,13 +17,18 @@
|
||||||
package org.springframework.beans.factory.support;
|
package org.springframework.beans.factory.support;
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor;
|
import java.beans.PropertyDescriptor;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectFactory;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,4 +128,55 @@ abstract class AutowireUtils {
|
||||||
return false;
|
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;
|
package org.springframework.beans.factory.support;
|
||||||
|
|
||||||
|
import java.io.ObjectStreamException;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -81,7 +85,14 @@ import org.springframework.util.StringUtils;
|
||||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||||
*/
|
*/
|
||||||
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
|
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 */
|
/** Whether to allow re-registration of a different definition with the same name */
|
||||||
private boolean allowBeanDefinitionOverriding = true;
|
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
|
* Set whether it should be allowed to override bean definitions by registering
|
||||||
* a different definition with the same name, automatically replacing the former.
|
* 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()) {
|
for (Class autowiringType : this.resolvableDependencies.keySet()) {
|
||||||
if (autowiringType.isAssignableFrom(requiredType)) {
|
if (autowiringType.isAssignableFrom(requiredType)) {
|
||||||
Object autowiringValue = this.resolvableDependencies.get(autowiringType);
|
Object autowiringValue = this.resolvableDependencies.get(autowiringType);
|
||||||
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
|
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
|
||||||
autowiringValue = ((ObjectFactory) autowiringValue).getObject();
|
|
||||||
}
|
|
||||||
if (requiredType.isInstance(autowiringValue)) {
|
if (requiredType.isInstance(autowiringValue)) {
|
||||||
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
|
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
|
||||||
break;
|
break;
|
||||||
|
@ -824,4 +847,46 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
return sb.toString();
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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";
|
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.
|
* Set the parent of this application context.
|
||||||
* <p>Note that the parent shouldn't be changed: It should only be set outside
|
* <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) {
|
catch (BeansException ex) {
|
||||||
// Destroy already created singletons to avoid dangling resources.
|
// Destroy already created singletons to avoid dangling resources.
|
||||||
beanFactory.destroySingletons();
|
destroyBeans();
|
||||||
|
|
||||||
// Reset 'active' flag.
|
// Reset 'active' flag.
|
||||||
cancelRefresh(ex);
|
cancelRefresh(ex);
|
||||||
|
@ -794,7 +794,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||||
* destroys the singletons in the bean factory of this application context.
|
* 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.
|
* <p>Called by both <code>close()</code> and a JVM shutdown hook, if any.
|
||||||
* @see org.springframework.context.event.ContextClosedEvent
|
* @see org.springframework.context.event.ContextClosedEvent
|
||||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
|
* @see #destroyBeans()
|
||||||
* @see #close()
|
* @see #close()
|
||||||
* @see #registerShutdownHook()
|
* @see #registerShutdownHook()
|
||||||
*/
|
*/
|
||||||
|
@ -803,6 +803,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info("Closing " + this);
|
logger.info("Closing " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Publish shutdown event.
|
// Publish shutdown event.
|
||||||
publishEvent(new ContextClosedEvent(this));
|
publishEvent(new ContextClosedEvent(this));
|
||||||
|
@ -810,15 +811,19 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
logger.error("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
|
logger.error("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop all Lifecycle beans, to avoid delays during individual destruction.
|
// Stop all Lifecycle beans, to avoid delays during individual destruction.
|
||||||
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
|
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
|
||||||
for (String beanName : new LinkedHashSet<String>(lifecycleBeans.keySet())) {
|
for (String beanName : new LinkedHashSet<String>(lifecycleBeans.keySet())) {
|
||||||
doStop(lifecycleBeans, beanName);
|
doStop(lifecycleBeans, beanName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy all cached singletons in the context's BeanFactory.
|
// Destroy all cached singletons in the context's BeanFactory.
|
||||||
destroyBeans();
|
destroyBeans();
|
||||||
|
|
||||||
// Close the state of this context itself.
|
// Close the state of this context itself.
|
||||||
closeBeanFactory();
|
closeBeanFactory();
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
synchronized (this.activeMonitor) {
|
synchronized (this.activeMonitor) {
|
||||||
this.active = false;
|
this.active = false;
|
||||||
|
|
|
@ -122,6 +122,7 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
DefaultListableBeanFactory beanFactory = createBeanFactory();
|
DefaultListableBeanFactory beanFactory = createBeanFactory();
|
||||||
|
beanFactory.setSerializationId(getId());
|
||||||
customizeBeanFactory(beanFactory);
|
customizeBeanFactory(beanFactory);
|
||||||
loadBeanDefinitions(beanFactory);
|
loadBeanDefinitions(beanFactory);
|
||||||
synchronized (this.beanFactoryMonitor) {
|
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
|
@Override
|
||||||
protected final void closeBeanFactory() {
|
protected final void closeBeanFactory() {
|
||||||
synchronized (this.beanFactoryMonitor) {
|
synchronized (this.beanFactoryMonitor) {
|
||||||
|
this.beanFactory.setSerializationId(null);
|
||||||
this.beanFactory = null;
|
this.beanFactory = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
||||||
*/
|
*/
|
||||||
public GenericApplicationContext() {
|
public GenericApplicationContext() {
|
||||||
this.beanFactory = new DefaultListableBeanFactory();
|
this.beanFactory = new DefaultListableBeanFactory();
|
||||||
|
this.beanFactory.setSerializationId(getId());
|
||||||
this.beanFactory.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer());
|
this.beanFactory.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer());
|
||||||
this.beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
this.beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||||
}
|
}
|
||||||
|
@ -149,6 +150,12 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
||||||
this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());
|
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
|
* Set a ResourceLoader to use for this context. If set, the context will
|
||||||
* delegate all <code>getResource</code> calls to the given ResourceLoader.
|
* 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.
|
* get released.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected final void closeBeanFactory() {
|
protected final void closeBeanFactory() {
|
||||||
|
this.beanFactory.setSerializationId(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,13 +16,13 @@
|
||||||
|
|
||||||
package org.springframework.aop.scope;
|
package org.springframework.aop.scope;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.aop.support.AopUtils;
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.beans.ITestBean;
|
import org.springframework.beans.ITestBean;
|
||||||
import org.springframework.beans.TestBean;
|
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.beans.factory.xml.XmlBeanFactory;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.util.SerializationTestUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rob Harrop
|
* @author Rob Harrop
|
||||||
|
@ -82,6 +83,7 @@ public class ScopedProxyTests {
|
||||||
@Test
|
@Test
|
||||||
public void testJdkScopedProxy() throws Exception {
|
public void testJdkScopedProxy() throws Exception {
|
||||||
XmlBeanFactory bf = new XmlBeanFactory(TESTBEAN_CONTEXT);
|
XmlBeanFactory bf = new XmlBeanFactory(TESTBEAN_CONTEXT);
|
||||||
|
bf.setSerializationId("X");
|
||||||
SimpleMapScope scope = new SimpleMapScope();
|
SimpleMapScope scope = new SimpleMapScope();
|
||||||
bf.registerScope("request", scope);
|
bf.registerScope("request", scope);
|
||||||
|
|
||||||
|
@ -91,14 +93,26 @@ public class ScopedProxyTests {
|
||||||
assertTrue(bean instanceof ScopedObject);
|
assertTrue(bean instanceof ScopedObject);
|
||||||
ScopedObject scoped = (ScopedObject) bean;
|
ScopedObject scoped = (ScopedObject) bean;
|
||||||
assertEquals(TestBean.class, scoped.getTargetObject().getClass());
|
assertEquals(TestBean.class, scoped.getTargetObject().getClass());
|
||||||
|
bean.setAge(101);
|
||||||
|
|
||||||
assertTrue(scope.getMap().containsKey("testBeanTarget"));
|
assertTrue(scope.getMap().containsKey("testBeanTarget"));
|
||||||
assertEquals(TestBean.class, scope.getMap().get("testBeanTarget").getClass());
|
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
|
@Test
|
||||||
public void testCglibScopedProxy() {
|
public void testCglibScopedProxy() throws Exception {
|
||||||
XmlBeanFactory bf = new XmlBeanFactory(LIST_CONTEXT);
|
XmlBeanFactory bf = new XmlBeanFactory(LIST_CONTEXT);
|
||||||
|
bf.setSerializationId("Y");
|
||||||
SimpleMapScope scope = new SimpleMapScope();
|
SimpleMapScope scope = new SimpleMapScope();
|
||||||
bf.registerScope("request", scope);
|
bf.registerScope("request", scope);
|
||||||
|
|
||||||
|
@ -107,9 +121,20 @@ public class ScopedProxyTests {
|
||||||
assertTrue(tb.getFriends() instanceof ScopedObject);
|
assertTrue(tb.getFriends() instanceof ScopedObject);
|
||||||
ScopedObject scoped = (ScopedObject) tb.getFriends();
|
ScopedObject scoped = (ScopedObject) tb.getFriends();
|
||||||
assertEquals(ArrayList.class, scoped.getTargetObject().getClass());
|
assertEquals(ArrayList.class, scoped.getTargetObject().getClass());
|
||||||
|
tb.getFriends().add("myFriend");
|
||||||
|
|
||||||
assertTrue(scope.getMap().containsKey("scopedTarget.scopedList"));
|
assertTrue(scope.getMap().containsKey("scopedTarget.scopedList"));
|
||||||
assertEquals(ArrayList.class, scope.getMap().get("scopedTarget.scopedList").getClass());
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,16 +16,16 @@
|
||||||
|
|
||||||
package org.springframework.context.annotation;
|
package org.springframework.context.annotation;
|
||||||
|
|
||||||
|
import example.scannable.FooService;
|
||||||
|
import example.scannable.ScopedProxyTestBean;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.aop.support.AopUtils;
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.beans.FatalBeanException;
|
import org.springframework.beans.FatalBeanException;
|
||||||
import org.springframework.beans.factory.config.SimpleMapScope;
|
import org.springframework.beans.factory.config.SimpleMapScope;
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
|
import org.springframework.util.SerializationTestUtils;
|
||||||
import example.scannable.FooService;
|
|
||||||
import example.scannable.ScopedProxyTestBean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Mark Fisher
|
* @author Mark Fisher
|
||||||
|
@ -54,7 +54,7 @@ public class ComponentScanParserScopedProxyTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInterfacesScopedProxy() {
|
public void testInterfacesScopedProxy() throws Exception {
|
||||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||||
"org/springframework/context/annotation/scopedProxyInterfacesTests.xml");
|
"org/springframework/context/annotation/scopedProxyInterfacesTests.xml");
|
||||||
context.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
context.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
||||||
|
@ -62,16 +62,26 @@ public class ComponentScanParserScopedProxyTests {
|
||||||
FooService bean = (FooService) context.getBean("scopedProxyTestBean");
|
FooService bean = (FooService) context.getBean("scopedProxyTestBean");
|
||||||
// should be dynamic proxy
|
// should be dynamic proxy
|
||||||
assertTrue(AopUtils.isJdkDynamicProxy(bean));
|
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
|
@Test
|
||||||
public void testTargetClassScopedProxy() {
|
public void testTargetClassScopedProxy() throws Exception {
|
||||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||||
"org/springframework/context/annotation/scopedProxyTargetClassTests.xml");
|
"org/springframework/context/annotation/scopedProxyTargetClassTests.xml");
|
||||||
context.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
context.getBeanFactory().registerScope("myScope", new SimpleMapScope());
|
||||||
ScopedProxyTestBean bean = (ScopedProxyTestBean) context.getBean("scopedProxyTestBean");
|
ScopedProxyTestBean bean = (ScopedProxyTestBean) context.getBean("scopedProxyTestBean");
|
||||||
// should be a class-based proxy
|
// should be a class-based proxy
|
||||||
assertTrue(AopUtils.isCglibProxy(bean));
|
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
|
@Test
|
||||||
|
|
|
@ -1,11 +1,21 @@
|
||||||
/*
|
/*
|
||||||
* The Spring Framework is published under the terms
|
* Copyright 2002-2009 the original author or authors.
|
||||||
* of the Apache Software License.
|
*
|
||||||
|
* 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;
|
package org.springframework.util;
|
||||||
|
|
||||||
import java.awt.Point;
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -13,20 +23,14 @@ import java.io.NotSerializableException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
import org.springframework.beans.TestBean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for testing serializability of objects.
|
* Utilities for testing serializability of objects.
|
||||||
* Exposes static methods for use in other test cases.
|
* Exposes static methods for use in other test cases.
|
||||||
* Extends TestCase only to test itself.
|
|
||||||
*
|
*
|
||||||
* @author Rod Johnson
|
* @author Rod Johnson
|
||||||
*/
|
*/
|
||||||
public class SerializationTestUtils extends TestCase {
|
public class SerializationTestUtils {
|
||||||
|
|
||||||
public static void testSerialization(Object o) throws IOException {
|
public static void testSerialization(Object o) throws IOException {
|
||||||
OutputStream baos = new ByteArrayOutputStream();
|
OutputStream baos = new ByteArrayOutputStream();
|
||||||
|
@ -55,43 +59,7 @@ public class SerializationTestUtils extends TestCase {
|
||||||
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
||||||
ObjectInputStream ois = new ObjectInputStream(is);
|
ObjectInputStream ois = new ObjectInputStream(is);
|
||||||
Object o2 = ois.readObject();
|
Object o2 = ois.readObject();
|
||||||
|
|
||||||
return o2;
|
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="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">
|
<bean id="requestScoped" class="test.beans.TestBean" scope="request">
|
||||||
<aop:scoped-proxy/>
|
<aop:scoped-proxy/>
|
||||||
<property name="name" value="Rob Harrop"/>
|
<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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,23 +17,24 @@
|
||||||
package org.springframework.aop.config;
|
package org.springframework.aop.config;
|
||||||
|
|
||||||
import static java.lang.String.format;
|
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.Before;
|
||||||
import org.junit.Test;
|
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.framework.Advised;
|
||||||
import org.springframework.aop.support.AopUtils;
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpSession;
|
import org.springframework.mock.web.MockHttpSession;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
import org.springframework.web.context.support.XmlWebApplicationContext;
|
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.
|
* Integration tests for scoped proxy use in conjunction with aop: namespace.
|
||||||
* Deemed an integration test because .web mocks and application contexts are required.
|
* Deemed an integration test because .web mocks and application contexts are required.
|
||||||
|
@ -47,7 +48,7 @@ import test.beans.TestBean;
|
||||||
public final class AopNamespaceHandlerScopeIntegrationTests {
|
public final class AopNamespaceHandlerScopeIntegrationTests {
|
||||||
|
|
||||||
private static final String CLASSNAME = AopNamespaceHandlerScopeIntegrationTests.class.getName();
|
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;
|
private ApplicationContext context;
|
||||||
|
|
||||||
|
@ -59,6 +60,20 @@ public final class AopNamespaceHandlerScopeIntegrationTests {
|
||||||
this.context = wac;
|
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
|
@Test
|
||||||
public void testRequestScoping() throws Exception {
|
public void testRequestScoping() throws Exception {
|
||||||
MockHttpServletRequest oldRequest = new MockHttpServletRequest();
|
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 pac =
|
||||||
(ConfigurablePortletApplicationContext) BeanUtils.instantiateClass(getContextClass());
|
(ConfigurablePortletApplicationContext) BeanUtils.instantiateClass(getContextClass());
|
||||||
|
pac.setId(getPortletContext().getPortletContextName() + "." + getPortletName());
|
||||||
pac.setParent(parent);
|
pac.setParent(parent);
|
||||||
pac.setPortletContext(getPortletContext());
|
pac.setPortletContext(getPortletContext());
|
||||||
pac.setPortletConfig(getPortletConfig());
|
pac.setPortletConfig(getPortletConfig());
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.web.portlet.context;
|
package org.springframework.web.portlet.context;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -120,24 +121,8 @@ public abstract class PortletApplicationContextUtils {
|
||||||
pc.setAttribute(PortletContextScope.class.getName(), appScope);
|
pc.setAttribute(PortletContextScope.class.getName(), appScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
beanFactory.registerResolvableDependency(PortletRequest.class, new ObjectFactory<PortletRequest>() {
|
beanFactory.registerResolvableDependency(PortletRequest.class, new RequestObjectFactory());
|
||||||
public PortletRequest getObject() {
|
beanFactory.registerResolvableDependency(PortletSession.class, new SessionObjectFactory());
|
||||||
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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 wac =
|
||||||
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());
|
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());
|
||||||
|
wac.setId(getServletContext().getServletContextName() + "." + getServletName());
|
||||||
wac.setParent(parent);
|
wac.setParent(parent);
|
||||||
wac.setServletContext(getServletContext());
|
wac.setServletContext(getServletContext());
|
||||||
wac.setServletConfig(getServletConfig());
|
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.IOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
@ -72,6 +73,7 @@ import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.ExtendedModelMap;
|
import org.springframework.ui.ExtendedModelMap;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
|
import org.springframework.util.SerializationTestUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.validation.Errors;
|
import org.springframework.validation.Errors;
|
||||||
|
@ -524,7 +526,7 @@ public class ServletAnnotationControllerTests {
|
||||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||||
wac.setServletContext(servletContext);
|
wac.setServletContext(servletContext);
|
||||||
RootBeanDefinition bd = new RootBeanDefinition(MyParameterDispatchingController.class);
|
RootBeanDefinition bd = new RootBeanDefinition(MyParameterDispatchingController.class);
|
||||||
bd.setScope(WebApplicationContext.SCOPE_REQUEST);
|
//bd.setScope(WebApplicationContext.SCOPE_REQUEST);
|
||||||
wac.registerBeanDefinition("controller", bd);
|
wac.registerBeanDefinition("controller", bd);
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(wac);
|
AnnotationConfigUtils.registerAnnotationConfigProcessors(wac);
|
||||||
wac.getBeanFactory().registerResolvableDependency(ServletConfig.class, servletConfig);
|
wac.getBeanFactory().registerResolvableDependency(ServletConfig.class, servletConfig);
|
||||||
|
@ -541,8 +543,8 @@ public class ServletAnnotationControllerTests {
|
||||||
assertEquals("myView", response.getContentAsString());
|
assertEquals("myView", response.getContentAsString());
|
||||||
assertSame(servletContext, request.getAttribute("servletContext"));
|
assertSame(servletContext, request.getAttribute("servletContext"));
|
||||||
assertSame(servletConfig, request.getAttribute("servletConfig"));
|
assertSame(servletConfig, request.getAttribute("servletConfig"));
|
||||||
assertSame(session, request.getAttribute("session"));
|
assertSame(session.getId(), request.getAttribute("sessionId"));
|
||||||
assertSame(request, request.getAttribute("request"));
|
assertSame(request.getRequestURI(), request.getAttribute("requestUri"));
|
||||||
|
|
||||||
request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do");
|
request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do");
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
|
@ -551,8 +553,8 @@ public class ServletAnnotationControllerTests {
|
||||||
assertEquals("myView", response.getContentAsString());
|
assertEquals("myView", response.getContentAsString());
|
||||||
assertSame(servletContext, request.getAttribute("servletContext"));
|
assertSame(servletContext, request.getAttribute("servletContext"));
|
||||||
assertSame(servletConfig, request.getAttribute("servletConfig"));
|
assertSame(servletConfig, request.getAttribute("servletConfig"));
|
||||||
assertSame(session, request.getAttribute("session"));
|
assertSame(session.getId(), request.getAttribute("sessionId"));
|
||||||
assertSame(request, request.getAttribute("request"));
|
assertSame(request.getRequestURI(), request.getAttribute("requestUri"));
|
||||||
|
|
||||||
request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do");
|
request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do");
|
||||||
request.addParameter("view", "other");
|
request.addParameter("view", "other");
|
||||||
|
@ -572,6 +574,11 @@ public class ServletAnnotationControllerTests {
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
servlet.service(request, response);
|
servlet.service(request, response);
|
||||||
assertEquals("mySurpriseView", response.getContentAsString());
|
assertEquals("mySurpriseView", response.getContentAsString());
|
||||||
|
|
||||||
|
MyParameterDispatchingController deserialized = (MyParameterDispatchingController)
|
||||||
|
SerializationTestUtils.serializeAndDeserialize(servlet.getWebApplicationContext().getBean("controller"));
|
||||||
|
assertNotNull(deserialized.request);
|
||||||
|
assertNotNull(deserialized.session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1265,13 +1272,13 @@ public class ServletAnnotationControllerTests {
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/myPath.do")
|
@RequestMapping("/myPath.do")
|
||||||
private static class MyParameterDispatchingController {
|
private static class MyParameterDispatchingController implements Serializable {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ServletContext servletContext;
|
private transient ServletContext servletContext;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ServletConfig servletConfig;
|
private transient ServletConfig servletConfig;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private HttpSession session;
|
private HttpSession session;
|
||||||
|
@ -1288,8 +1295,8 @@ public class ServletAnnotationControllerTests {
|
||||||
response.getWriter().write("myView");
|
response.getWriter().write("myView");
|
||||||
request.setAttribute("servletContext", this.servletContext);
|
request.setAttribute("servletContext", this.servletContext);
|
||||||
request.setAttribute("servletConfig", this.servletConfig);
|
request.setAttribute("servletConfig", this.servletConfig);
|
||||||
request.setAttribute("session", this.session);
|
request.setAttribute("sessionId", this.session.getId());
|
||||||
request.setAttribute("request", this.request);
|
request.setAttribute("requestUri", this.request.getRequestURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(params = {"view", "!lang"})
|
@RequestMapping(params = {"view", "!lang"})
|
||||||
|
|
|
@ -247,6 +247,7 @@ public class ContextLoader {
|
||||||
|
|
||||||
ConfigurableWebApplicationContext wac =
|
ConfigurableWebApplicationContext wac =
|
||||||
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
|
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
|
||||||
|
wac.setId(servletContext.getServletContextName());
|
||||||
wac.setParent(parent);
|
wac.setParent(parent);
|
||||||
wac.setServletContext(servletContext);
|
wac.setServletContext(servletContext);
|
||||||
wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM));
|
wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM));
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.web.context.support;
|
package org.springframework.web.context.support;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -150,25 +151,8 @@ public abstract class WebApplicationContextUtils {
|
||||||
sc.setAttribute(ServletContextScope.class.getName(), appScope);
|
sc.setAttribute(ServletContextScope.class.getName(), appScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
beanFactory.registerResolvableDependency(ServletRequest.class, new ObjectFactory<ServletRequest>() {
|
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
|
||||||
public ServletRequest getObject() {
|
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
|
||||||
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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (jsfPresent) {
|
if (jsfPresent) {
|
||||||
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
|
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.
|
* Inner class to avoid hard-coded JSF dependency.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue